---
name: reference-fred-ecb-hybrid-calendar-implementation-2026-06-12
description: WIC /api/economic-calendar の FRED + ECB SDW hybrid 実装 reference (15 + 3 = 18 live series, ECB policy rate v0.2 候補)
metadata: 
  node_type: memory
  type: reference
  originSessionId: f97b8504-aa0d-4a2f-b6a9-536a9908c71c
---

# WIC Economic Calendar FRED + ECB SDW hybrid 実装 reference

2026-06-12 WIC commit `0bdd430` + `762e4e4` で実装. Finnhub Economic Calendar が free tier から外れた (HTTP 403) ことを受け、 central-bank-grade free 2 source による hybrid backbone に切替.

## Live verified data series

### US backbone — FRED (15 series, FRED_KEY 既 bind, /api/fred と共有)

| seriesId | title | impact | unit |
|---|---|---|---|
| CPIAUCSL | CPI Index (All Items, SA) | High | (none) |
| CPILFESL | Core CPI Index (Less Food & Energy) | High | (none) |
| PCEPI | PCE Price Index | High | (none) |
| PCEPILFE | Core PCE Price Index | High | (none) |
| PAYEMS | Nonfarm Payrolls (Thousands) | High | (none) |
| UNRATE | Unemployment Rate | High | % |
| FEDFUNDS | Effective Fed Funds Rate | High | % |
| GDP | GDP (Billions USD, Nominal) | High | (none) |
| RSXFS | Retail Sales ex-Food Svc (Millions USD) | Medium | (none) |
| ICSA | Initial Jobless Claims | Medium | (none) |
| INDPRO | Industrial Production Index | Medium | (none) |
| HOUST | Housing Starts (Thousands of Units) | Medium | (none) |
| DGS10 | 10-Year Treasury Yield | Low | % |
| DGS2 | 2-Year Treasury Yield | Low | % |
| DCOILWTICO | WTI Crude Oil Spot Price | Low | $ |

**FRED unit convention 重要 honest**: FRED は base unit で raw 値を返す (PAYEMS = "Thousands of Persons" なので 158300 raw が意味するのは 158.3M jobs)。 'K'/'M'/'B' suffix を追加すると scale 重複表記で誤読を招く (158300 + 'K' = 「158B jobs」 と誤読される)。 ゆえに本実装では suffix = '%' (rate) と '$' (price) のみ、 count-style series は scale を title に inline (例: 「Nonfarm Payrolls (Thousands)」). 詳細は commit `762e4e4` 参照.

### EU backbone — ECB SDW (3 series, keyless, public access)

| dataflow/key | title | impact | unit | latest (2026-06-11 probe) |
|---|---|---|---|---|
| `ICP/M.U2.N.000000.4.ANR` | HICP CPI (Eurozone, YoY) | High | % | 1.9% @ 2025-12 |
| `ICP/M.U2.N.XEF000.4.ANR` | HICP Core CPI (Eurozone, YoY) | High | % | 2.3% @ 2025-12 |
| `BSI/M.U2.Y.V.M30.X.I.U2.2300.Z01.A` | M3 Money Supply (Eurozone, YoY) | Low | % | 2.74% @ 2026-04 |

### JP backbone — 当面 empty

BOJ は専用 JSON time-series API なし (stat-search.boj.or.jp は legacy CGI + Shift_JIS HTML). v0.2 候補:
- OECD Main Economic Indicators (MEI)
- IMF SDMX API
- e-Stat (政府統計の総合窓口) API

## ECB policy rate — v0.2 候補 (EMPTY-series probe failed)

2026-06-11 probe で以下 5 key signature variants 全 EMPTY-series を返した (HTTP 200 + `series: {}`):

| 試した key | 結果 |
|---|---|
| `FM/D.U2.EUR.4F.KR.MRR_FR.LEV` | EMPTY |
| `FM/B.U2.EUR.4F.KR.MRR_FR.LEV` | EMPTY |
| `FM/M.U2.EUR.4F.KR.MRR_FR.LEV` | EMPTY |
| `FM/D.U2.EUR.4F.KR.DFR.LEV` | EMPTY |
| `FM/M.U2.EUR.4F.KR.DFR.LEV` | EMPTY |
| `FM/D.U2.EUR.4F.KR.MLFR.LEV` | EMPTY |

ECB SDW dataflow signature が SDMX 2.1 → 3.0 移行で変わった可能性。 v0.2 で fact-check 再実施:
1. ECB SDW data portal (https://data.ecb.europa.eu) で MRR/DFR の current series id を確認
2. SDMX dataflow query で current key system 取得
3. live verify 後 ECB_SERIES に追加

## 設計原則 (本 hybrid 実装で確立)

### 1. 「release archive」 framing (forward-looking schedule でない)

Finnhub 時代は forward (next 7 日) 込みだったが、 FRED/ECB は release history のみ。 contract 変更:
- `range=all` default で「最新 release per series」
- `range=24h/week` 解釈 = 「過去 N 日以内 release」
- forecast 欄は '' (consensus を持たないので honest empty)
- surprise = actual − previous (forecast fallback)

### 2. parallel fetch + graceful degradation

```ts
const [fredResult, ecbResult] = await Promise.allSettled([
  fetchAllFredEvents(env.FRED_KEY),
  fetchAllEcbEvents(),
]);
```

一方失敗で他方継続. `backbones: { fred: {fetched, errors}, ecb: {fetched, errors} }` を response に同梱.

### 3. cache poisoning 防止

両方 empty (HTTP 503 相当) の場合 cache に store しない. 一時的 upstream blip が 1 時間 edge cache を支配する事態を防ぐ.

### 4. FRED unit honest

count-series scale を title に fold する (suffix で乗算しない). reader が FRED convention を知らずに値を読んでも誤読しない. 詳細上記.

## ECB SDW JSON shape (parse reference)

```
{
  "dataSets": [
    {
      "series": {
        "<dimKey>": {
          "observations": {
            "0": [value0, ...attrs],
            "1": [value1, ...attrs],
            ...
          }
        }
      }
    }
  ],
  "structure": {
    "dimensions": {
      "observation": [
        {
          "values": [
            { "id": "2025-12", "start": "...", "end": "..." },
            ...
          ]
        }
      ]
    }
  }
}
```

- `series` が `{}` (空 object) = data 不在 (key signature 古い or empty result)
- observations index は string ("0", "1", ...), positional, time order は `structure.dimensions.observation[0].values[index]` の id
- `lastNObservations=2` は oldest-first 返す → 最新は最大 index

## D1 events table interaction

`events` table schema (Stage 2-α D1, 既存):

```sql
CREATE TABLE events (
  event_key TEXT PRIMARY KEY,
  date TEXT NOT NULL,
  currency TEXT NOT NULL,
  title TEXT NOT NULL,
  impact TEXT,
  forecast TEXT,
  actual TEXT,
  previous TEXT,
  captured_at TEXT
);
```

★ title rename 影響: 2026-06-12 unit honest fix で title が変わった (`Nonfarm Payrolls` → `Nonfarm Payrolls (Thousands)`)。 旧 title の D1 row と新 title の releases は **join できない** (history sparse になる). 受け入れ判断: archive は ~1 month で再蓄積. migration script (旧 title → 新 title rename) は title set 安定後 v0.2 で.

## 関連 commit

- `0bdd430` economic-calendar: switch from Finnhub to FRED + ECB SDW hybrid
- `762e4e4` economic-calendar: honest FRED unit handling

## 関連 memory

- [[project-wic-finnhub-economic-calendar-outage-pending-source-switch]] 切替の経緯
- [[reference-finnhub-economic-calendar-actuals-2026-05-30]] 前回切替時の知見 (一部 outdated)
- [[reference-wic-free-market-data-apis-2026-05-25]] free API map
