70 lines
3.6 KiB
JavaScript
70 lines
3.6 KiB
JavaScript
// 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;
|
||
}
|