finance-dashboard/lib/calendar-fred.js

70 lines
3.6 KiB
JavaScript
Raw Normal View History

2026-06-03 16:42:07 +00:00
// FRED 發布日程:補足 BLS/BEA 未涵蓋的重要美國總經零售、房市、ADP、初領失業金等
const UA = 'finance-dashboard/1.0';
const FRED_RELEASES = [
{ id: 9, title: '零售銷售', impact: 'medium', time: '08:30 美東', note: '全美零售與餐飲銷售,反映內需動能' },
{ id: 13, title: '工業生產 / 產能利用率', impact: 'medium', time: '09:15 美東', note: '工廠產出與產能使用率,景氣先行指標' },
{ id: 91, title: '密西根消費者信心', impact: 'medium', time: '10:00 美東', note: '消費者對景氣與通膨的預期,影響風險偏好' },
{ id: 27, title: '新屋開工 / 營建許可', impact: 'medium', time: '08:30 美東', note: '住宅建築活動,利率敏感指標' },
{ id: 291, title: '成屋銷售', impact: 'medium', time: '10:00 美東', note: '既有住宅成交,觀察房市需求' },
{ id: 95, title: '耐久財 / 工廠接單出貨', impact: 'medium', time: '08:30 美東', note: '企業資本支出與製造需求' },
{ id: 14, title: '消費信貸', impact: 'low', time: '15:00 美東', note: '家庭與信用卡借款,觀察消費支撐' },
{ id: 180, title: '初領失業救濟金', impact: 'medium', time: '08:30 美東', note: '每週勞動市場溫度,突增常引發避險' },
{ id: 194, title: 'ADP 私部門就業', impact: 'medium', time: '08:15 美東', note: '非農公布前的私部門就業參考' },
{ id: 351, title: '費城 Fed 製造業指數', impact: 'medium', time: '08:30 美東', note: '製造業景氣調查PMI 類指標' },
{ id: 352, title: '非製造業景氣調查', impact: 'medium', time: '10:00 美東', note: '服務業活動,占美國經濟比重大' },
{ id: 219, title: '芝加哥 Fed 全國活動指數', impact: 'low', time: '08:30 美東', note: '綜合 85 項經濟指標的月度摘要' },
{ id: 11, title: '就業成本指數 ECI', impact: 'medium', time: '08:30 美東', note: '薪資與福利成本Fed 關注的通膨壓力' },
{ id: 16, title: '生產力與單位成本', impact: 'medium', time: '08:30 美東', note: '企業效率與人工成本,影響獲利與通膨' },
];
function getFredKey() {
const key = process.env.FRED_API_KEY;
if (!key || key === 'your_fred_api_key_here') return null;
return key;
}
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function fetchReleaseDates(releaseId, key) {
const url = `https://api.stlouisfed.org/fred/release/dates?release_id=${releaseId}` +
`&include_release_dates_with_no_data=true&limit=100&sort_order=desc&api_key=${key}&file_type=json`;
for (let attempt = 0; attempt < 3; attempt++) {
const res = await fetch(url, { headers: { 'User-Agent': UA } });
if (res.status === 429) {
await sleep(800 * (attempt + 1));
continue;
}
if (!res.ok) throw new Error(`FRED release ${releaseId} HTTP ${res.status}`);
const data = await res.json();
return (data.release_dates || []).map((row) => row.date);
}
throw new Error(`FRED release ${releaseId} rate limited`);
}
export async function fetchFredMacroEvents(start, end) {
const key = getFredKey();
if (!key) return [];
const events = [];
for (const rel of FRED_RELEASES) {
try {
const dates = await fetchReleaseDates(rel.id, key);
for (const date of dates) {
if (date < start || date > end) continue;
events.push({
date,
time: rel.time,
title: rel.title,
category: 'macro',
impact: rel.impact,
source: 'FRED releases',
note: rel.note,
});
}
} catch {
// 單一來源失敗不阻擋整體日曆
}
await sleep(300);
}
return events;
}