你可以把 Narwhal 的节假日、发布日期、经济数据、大宗商品现货价格、汇率和预测市场赔率导入 Postgres。用 curl 获取 JSON,用 jq 转成 CSV,再用 psql 载入暂存表并 upsert 行。
你将完成的设置
在这个工作流中,Postgres 是数据的目标库,最终你会得到每个数据领域各自的 CSV 文件,以及一张支持重复导入的节假日表。Postgres 本身无法获取 HTTP 内容,所以请求要在导入数据库之前在 shell 中完成。你需要 curl、jq 和 psql。获取命令共用一个辅助函数来处理 API URL 和授权标头;数据库示例会先使用临时暂存表,再写入节假日表。导出时,节假日、发布日期、CPI、大宗商品价格、汇率和政策利率路径赔率分别存入单独的文件,并为每个领域选取对应的响应字段。
设置你的 API 密钥
- 创建免费密钥 在 Narwhal 注册页 创建你的免费密钥。Narwhal 用同一个账户和同一个 API 密钥覆盖节假日、经济日历、经济数据、大宗商品现货价格、汇率和预测市场赔率。
- 把密钥存入环境变量 在运行获取命令的 shell 中,把密钥保存在名为
NARWHAL_API_KEY的环境变量里。辅助函数每次发送请求时都会读取这个变量,所以同一个密钥适用于所有 CSV 导出。 - 使用共用的请求辅助函数 这些命令通过
Authorization: Bearer YOUR_KEY标头把密钥发送到https://api.narwhalapi.com。REST 和 MCP 共用同一个密钥。对于这个 Postgres 工作流,请在通过psql导入生成的文件之前,先在 shell 辅助函数中使用 REST 请求。
用代码获取数据
- 把每个领域获取为 CSV 运行 shell 命令请求各个领域,并用
jq选取响应字段。辅助函数使用curl -f,因此遇到 HTTP 错误状态时会失败。每条管道都会写出一个 CSV 文件,列的顺序与其jq表达式中的字段顺序一致。节假日变成日期和名称两列,CPI 变成期间和数值两列。为某个文件定义暂存表时,请保持这个顺序。get() { curl -sf -H "Authorization: Bearer $NARWHAL_API_KEY" \ "https://api.narwhalapi.com$1" } get /v1/calendars/holidays/USA/2026 \ | jq -r '.holidays[] | [.date, .name] | @csv' \ > holidays.csv get \ "/v1/economics/calendar?countries=USA&start_date=2026-11-01&end_date=2026-11-30&limit=100" \ | jq -r '.releases[] | [.at, .period, .topic, .status] | @csv' > releases.csv get "/v1/economics/USA/cpi/observations?start=2025-09" \ | jq -r '.observations[] | [.period, .value] | @csv' \ > cpi.csv get /v1/commodities/spot/BRENT/USD | jq -r '[(now | todate), .price] | @csv' > brent.csv get "/v1/fx/rates/USD?currencies=EUR,IDR" \ | jq -r '.rates[] | [.currency, .rate, .timestamp] | @csv' \ > fx.csv get /v1/predictions/policy-paths/federal-reserve \ | jq -r '.meetings[] | [.resolves_at, .p_cut, .p_hold, .p_hike] | @csv' \ > fed.csv - 通过暂存表导入节假日 在
psql能读取holidays.csv的位置运行导入命令。它会在需要时创建目标表,把 CSV 复制到临时表,再插入暂存的行。DISTINCT ON会去掉同一次导入中重复的日期。如果目标表中已存在某个日期,ON CONFLICT会更新它的名称。其他 CSV 文件也可以用同样的导入模式,只需使用与其字段匹配的表和主键。节假日目标表有一个类型为date的date列和一个类型为text的name列。它的暂存表与 CSV 的列顺序相同。psql <<'SQL' CREATE TABLE IF NOT EXISTS holidays (date date PRIMARY KEY, name text); CREATE TEMP TABLE staging (date date, name text); \copy staging FROM 'holidays.csv' WITH (FORMAT csv) INSERT INTO holidays SELECT DISTINCT ON (date) date, name FROM staging ORDER BY date, name ON CONFLICT (date) DO UPDATE SET name = EXCLUDED.name; SQL
按计划定时运行
用每天运行的 cron 行来执行脚本。把获取步骤放在数据库导入之前,这样 \copy 读取时 CSV 已经就绪,并让脚本可以使用 NARWHAL_API_KEY。由于导入使用 upsert,重新运行是安全的:已有的节假日日期会更新名称。对于其他文件,请使用各自的主键,而不是原样照搬节假日的主键。CPI 使用 period;汇率同时使用 currency 和 timestamp。扩展定时导入时,请让 CSV 字段顺序与各暂存表保持一致。
Postgres 中的节假日
请求 2026 年 USA 的节假日并读取 holidays 数组。每一项都有 date 和 name,它们就是 holidays.csv 的列。暂存表示例使用的就是这个文件。目标表以节假日日期作为主键,重复导入时会更新该日期的名称。
get() {
curl -sf -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com$1"
}
get /v1/calendars/holidays/USA/2026 \
| jq -r '.holidays[] | [.date, .name] | @csv' > holidays.csvPostgres 中的发布日期
请求 2026 年 11 月 USA 的经济日历并读取 releases。这些就是发布日期。请在 CSV 中保留 at、period、topic 和 status,让数据库中同时有发布时间及其主题和期间。请求的 URL 包含开始日期和结束日期,输出写入 releases.csv。
get() {
curl -sf -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com$1"
}
get \
"/v1/economics/calendar?countries=USA&start_date=2026-11-01&end_date=2026-11-30&limit=100" \
| jq -r '.releases[] | [.at, .period, .topic, .status] | @csv' > releases.csvPostgres 中的经济数据
请求从 2025 年 9 月起的 USA CPI 观测值并读取 observations。示例把每个 period 和 value 写入 cpi.csv。对这个序列,请把 period 用作目标表的主键。数值以十进制字符串形式返回,所以导入 Postgres 时请使用 numeric 列。period 列用来标识 upsert 要更新的观测值。
get() {
curl -sf -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com$1"
}
get "/v1/economics/USA/cpi/observations?start=2025-09" \
| jq -r '.observations[] | [.period, .value] | @csv' > cpi.csvPostgres 中的大宗商品现货价格
请求以 USD 计价的 BRENT 现货价格并读取 price。CSV 表达式用 jq 添加一个时间戳,并把它放在 brent.csv 中价格的前面;这个时间戳来自表达式。请把价格存入 numeric 列。现货代码包括 XAU、XAG、XPT、XPD、XCU、BRENT 和 WTI 等。
get() {
curl -sf -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com$1"
}
get /v1/commodities/spot/BRENT/USD \
| jq -r '[(now | todate), .price] | @csv' > brent.csvPostgres 中的汇率
请求以 USD 为基准货币的 EUR 和 IDR 汇率并读取 rates。CSV 按 currency、rate、timestamp 的顺序保存。对于目标表,请把 currency 和 timestamp 一起作为主键,并把十进制汇率存入 numeric 列。生成的 fx.csv 通过它自己的暂存表导入。
get() {
curl -sf -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com$1"
}
get "/v1/fx/rates/USD?currencies=EUR,IDR" \
| jq -r '.rates[] | [.currency, .rate, .timestamp] | @csv' > fx.csvPostgres 中的预测市场赔率
请求美联储政策利率路径并读取 meetings。CSV 的每一行保留某次会议的 resolves_at、p_cut、p_hold 和 p_hike。输出写入 fed.csv。把这个导入改成预测市场赔率表时,请按同样的顺序定义暂存列,并对十进制数值使用 numeric。
get() {
curl -sf -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com$1"
}
get /v1/predictions/policy-paths/federal-reserve \
| jq -r '.meetings[] | [.resolves_at, .p_cut, .p_hold, .p_hike] | @csv' > fed.csv为什么直接复制到节假日表可能会失败?
\copy 遇到重复键会失败。临时暂存表会先接收这些行,再由插入语句处理重复。在节假日示例中,如果单个文件里有重复日期,日期和名称的排序决定了保留哪个名称。之后,upsert 处理目标表中已有的日期。
价格应该怎么存储?
十进制数以字符串形式返回。把价格导入 Postgres 时,请将其转换为 numeric。CSV 只是传输格式;价格在数据库中如何存储,由目标列决定。这些导出中的 CPI 数值和汇率也请采用同样的十进制列方案。
发布于。