日銀の時系列統計APIをClaude Codeで呼ぶ — 系列コードを確かめて金利・為替・物価を取得
日本銀行の時系列統計データ検索サイトのAPIで、メタデータAPIから系列コードを確かめ、コードAPIで金利・為替・物価を取る手順。取得上限、続きの取り方、公開時の条件も書きます。
日本銀行の時系列統計データ検索サイトには、金利・為替・物価などの時系列をJSONやCSVで取得できるAPIがあります。利用にユーザー登録もAPIキーも要りません。Claude Codeに取得スクリプトを書かせれば、検索画面でCSVを落とす作業は置き換えられます。
ただし、取得の成否を分けるのは系列コードです。「ドル円の日次」を指すコードは名前から推測できず、同じDBの中に日次と月次が混ざっています。この記事は、系列コードを自分で確かめる手順を軸に、取得スクリプト、上限の越え方、Claudeに守らせる規約までを順に扱います。
日銀の時系列統計APIでできること
APIは3種類あり、指定する条件が違います。
| API | 取得するもの |
|---|---|
| コードAPI | 取得するもの時系列統計データ |
| 階層API | 取得するもの時系列統計データ |
| メタデータAPI | 取得するもの系列の属性情報 |
メタ情報とは、系列コードや系列名称などの属性です。メタデータAPIの結果は、コードAPIと階層APIのパラメータを作る材料になります。エンドポイントは https://www.stat-search.boj.or.jp/api/v1/ の下に getDataCode、getDataLayer、getMetadata を置く形で、大文字小文字を区別します。
取得できる範囲は、検索画面と同じ全データです。一括ダウンロードファイルが物価統計・資金循環統計・短観・国際収支統計・BIS関連統計に限られるのに対し、APIにはその制限がありません。出力形式はJSON(既定)とCSVで、言語は日本語(既定)と英語です。
データの更新は、原則として8時50分頃です。業務の都合で遅れることがあるため、毎朝の定時取得は9時台以降に置くと取りこぼしを避けられます。
系列コードは名前から推測できない
系列コードは、時系列の系列を特定する固有のコードです。公式の例は MADR1Z@D で、検索画面のデータコード検索では、先頭にDB名を付けた IR01'MADR1Z@D の形が出てきます。
APIに渡すのは、DB名を除いた系列コードだけです。データコードのまま渡すとエラーになり、STATUSは400、MESSAGEIDは M181001E(Invalid input parameters)が返ります。検索画面からコピーしたコードがそのまま通らない、というつまずきです。
Claudeに「ドル円の系列コードを教えて」と聞いても、答えは信用できません。日銀の系列コードは記憶から再現できる規則的な文字列ではないからです。実在しないコードを渡すと M181013E(指定した系列コードは存在しません)で止まりますが、実在するが別物のコードを渡すと、エラーなしで別の系列が返ります。止まらない取り違えのほうが厄介です。
メタデータAPIで系列コードを確かめる
コードを確かめる正式な経路が、メタデータAPIです。DB名を渡すと、そのDBの全系列の系列コード、系列名称、単位、期種、収録開始期・終了期、最終更新日などが返ります。
主なDB名は次のとおりです。分野ごとにDBが分かれているので、まず「どのDBか」を決めます。
| 知りたいもの | DB名 |
|---|---|
| 無担保コールO/Nレート | DB名FM01 |
| 短期市場の金利 | DB名FM02 |
| 基準割引率・基準貸付利率 | DB名IR01 |
| 貸出の平均金利 | DB名IR04 |
| 外国為替 | DB名FM08 |
| 実効為替レート | DB名FM09 |
| 企業物価指数 | DB名PR01 |
| 企業向けサービス価格指数 | DB名PR02 |
| マネタリーベース | DB名MD01 |
| 短観 | DB名CO |
メタデータAPIのCSVを日本語で取ると、先頭に処理結果の行(STATUS、MESSAGEID、MESSAGE、DATE、DB)があり、その後ろに SERIES_CODE から始まる見出し行が続きます。文字コードは日本語がShift-JIS、英語がUTF-8です。JSONで取れば文字コードに悩まずに済みますが、メタ情報は表形式のCSVのほうが検索しやすい場面が多くあります。
curl -s --compressed -H "Accept-Encoding: gzip" \
"https://www.stat-search.boj.or.jp/api/v1/getMetadata?format=csv&lang=jp&db=fm08" \
| iconv -f SHIFT_JIS -t UTF-8 > fm08_meta.csv外国為替市況(FM08)のメタ情報を見ると、同じDBに日次と月次が同居しているとわかります。たとえば FXERD04(東京市場 ドル・円 スポット17時時点)の収録開始期は 19980105 で日次、FXERM06(同 月末)は 197301 で月次です。名前が似ていて期種が違う系列が並ぶので、コードを選ぶときは名称だけでなく、期種・単位・収録期間も一緒に見ます。
物価のPR01は、メタ情報だけで3万行を超えます。全体をClaudeに読ませると文脈を無駄に使うため、スクリプトで名称を絞り込んでから、候補だけを見せる形にします。メタ情報の行には、系列コードが空欄で階層の見出しだけを示す行も混ざります。
コードAPIで金利・為替・物価を取る
系列コードが決まったら、コードAPIでデータを取ります。必須のパラメータは db と code の2つで、ほかは任意です。
| パラメータ | 内容 | 備考 |
|---|---|---|
format | 内容json または csv | 備考省略時はJSON |
lang | 内容jp または en | 備考省略時は日本語 |
db | 内容DB名 | 備考必須 |
code | 内容系列コード | 備考必須 |
startDate | 内容開始期 | 備考任意 |
endDate | 内容終了期 | 備考任意 |
startPosition | 内容検索開始位置 | 備考任意。続きを取るときに指定 |
開始期と終了期の書式は、系列の期種で変わります。暦年・年度は YYYY、半期は YYYYHH(HHは01か02)、四半期は YYYYQQ(QQは01〜04)、月次は YYYYMM です。週次と日次の系列でも、パラメータは月次形式の YYYYMM で渡します。日次の系列に 20250901 のような日単位の書式を渡すと、開始期の形式が期種と合わないとして M181015E が返ります。
公式の例には、無担保コールO/Nレートを取るURLが載っています。
https://www.stat-search.boj.or.jp/api/v1/getDataCode?db=FM01&code=STRDCLUCON,STRDCLUCONH,STRDCLUCONL&startDate=202501出力のJSONでは、系列ごとに SERIES_CODE、系列名称、単位、期種、最終更新日があり、VALUES の中に時期の配列 SURVEY_DATES と値の配列 VALUES が並びます。2つの配列は位置で対応します。データがない時期は null です。検索画面の結果で出る「NA」「ND」とは表記が違います。
期種は、出力では DAILY、MONTHLY のような正式名称で表示されます。ところが階層APIの frequency パラメータには、D、M、Q などの略称しか使えません。出力に出た正式名称をそのまま入力に使うとエラーになります。
取得上限と、続きの取り方
コードAPIには、1回のリクエストで取れる量に上限があります。
| 上限 | 値 | 超えたとき |
|---|---|---|
| 1回の系列数(コードAPI・階層API) | 値250件 | 超えたとき上限まで出力し、NEXTPOSITION に続きの位置が入る |
| 1回のデータ数(系列数×期数) | 値60,000件 | 超えたとき同上 |
| 階層APIで絞り込まれる系列数 | 値1,250件 | 超えたときエラーで、出力ファイルは作られない |
データ数には、欠損で null になる時期も含まれます。系列数かデータ数のどちらかが上限を超えると、上限までのデータが出力され、続きの位置が NEXTPOSITION に入ります。NEXTPOSITION がJSONで null(CSVではブランク)なら、全部取れています。
続きを取るには、同じパラメータに startPosition を足して再リクエストします。コードAPIでは、指定した系列コードの並び順がそのまま位置になります。たとえば200件の系列を指定し、160番目のコードから続けたいなら、startPosition=160 です。
250件を超える系列は、250件ずつに分けて、それぞれで NEXTPOSITION が消えるまで繰り返します。連続リクエストでは、必ず間隔を空けます。公式は高頻度のアクセスを避けるよう求めており、遮断される可能性があると明記しています。
Claude Codeに渡す前提を置く
ここまでの仕様のうち、Claudeが勝手に省きやすい点は、推測で動かれると困ります。次の内容をプロジェクトの CLAUDE.md に書いておきます。
## 日銀時系列統計APIの扱い
- 系列コードはメタデータAPI(getMetadata)の結果から選ぶ。記憶や推測で書かない
- 系列コードにDB名は付けない(IR01'MADR1Z@D ではなく MADR1Z@D)
- 1回のcodeには同じ期種の系列だけを入れる。250件を超えたら分割する
- NEXTPOSITIONが空になるまで続きを取る。リクエスト間は2秒以上空ける
- 数値を報告するときは、DB名・系列コード・系列名称・単位・期間を併記する
- STATUSが200以外なら、条件を変えずに止めてMESSAGEIDを報告する実行権限も絞れます。公式のpermissionsでは、WebFetch(domain:example.com) の形でドメインを指定でき、ほかに Bash(...) で実行するコマンドも許可できます。日銀のAPIに触れるのは取得スクリプトだけにして、許可もスクリプトに限ると、Claudeが任意のURLを叩く余地が減ります。
{
"permissions": {
"allow": [
"Bash(python3 scripts/boj_fetch.py *)",
"WebFetch(domain:www.stat-search.boj.or.jp)"
]
}
}権限ルールの管理は、/permissionsコマンドの記事にまとまっています。
取得スクリプトの例
次のスクリプトは、標準ライブラリだけで動く最小形です。メタデータAPIから系列名で候補を絞り込み、コードAPIで NEXTPOSITION を追いかけます。エラー時のJSONはHTTPの400や503の本文に入って返るため、HTTPError を捕まえて本文を読んでいます。Accept-Encoding: gzip を付けて通信量を減らし、リクエストごとに2秒空けます。日次の外国為替と月次の企業物価指数に対して、手元で実行して動作を確認した形です。
import csv, gzip, io, json, sys, time
from urllib.parse import urlencode
from urllib.error import HTTPError
from urllib.request import Request, urlopen
BASE = "https://www.stat-search.boj.or.jp/api/v1"
HEADERS = {"Accept-Encoding": "gzip"}
PAUSE = 2 # 連続リクエストの間隔(秒)
def get(path, **params):
time.sleep(PAUSE)
req = Request(f"{BASE}/{path}?{urlencode(params, safe=',*')}",
headers=HEADERS)
try:
res = urlopen(req, timeout=60)
except HTTPError as e: # エラー内容は本文(JSON)に入る
res = e
raw = res.read()
if res.headers.get("Content-Encoding") == "gzip":
raw = gzip.decompress(raw)
return raw
def search_series(db, keyword):
"""メタデータAPIから系列名で絞り込む"""
r = get("getMetadata", format="csv", lang="jp", db=db)
text = r.decode("shift_jis", errors="replace")
rows = list(csv.reader(io.StringIO(text)))
head = next(i for i, x in enumerate(rows) if x[:1] == ["SERIES_CODE"])
cols = rows[head]
for row in rows[head + 1:]:
d = dict(zip(cols, row))
if d.get("SERIES_CODE") and keyword in d["NAME_OF_TIME_SERIES_J"]:
yield d
def fetch(db, codes, start=None, end=None):
"""コードAPI。NEXTPOSITIONが出る間は続きを取る"""
pos, out = 1, []
while pos:
params = dict(db=db, code=",".join(codes))
if start: params["startDate"] = start
if end: params["endDate"] = end
if pos > 1: params["startPosition"] = pos
body = json.loads(get("getDataCode", **params))
if body["STATUS"] != 200:
sys.exit(f'{body["MESSAGEID"]}: {body["MESSAGE"]}')
out += body["RESULTSET"]
pos = body["NEXTPOSITION"]
return out
if __name__ == "__main__":
cmd, db, arg = sys.argv[1:4]
if cmd == "search": # python3 boj_fetch.py search FM08 17時時点
for d in search_series(db, arg):
print(d["SERIES_CODE"], d["NAME_OF_TIME_SERIES_J"], d["UNIT_J"],
d["START_OF_THE_TIME_SERIES"], d["END_OF_THE_TIME_SERIES"])
else: # python3 boj_fetch.py get FM08 FXERD04 202509
for s in fetch(db, arg.split(","), *sys.argv[4:6]):
v = s["VALUES"]
print(s["SERIES_CODE"], s["UNIT_J"], s["FREQUENCY"],
list(zip(v["SURVEY_DATES"], v["VALUES"]))[:3])呼び出し側では、まず候補を一覧にしてから取得します。
python3 scripts/boj_fetch.py search FM08 "17時時点"
python3 scripts/boj_fetch.py get FM08 FXERD04 202509 202509手元でこの絞り込みを実行すると、FXERD04(ドル・円17時時点、日次)、FXERD34(ユーロ・ドル17時時点、日次)、FXERM06(ドル・円17時時点/月末、月次)、FXERM07(同 月中平均、月次)の4件が出ました。日次と月次が混ざっているので、日次を選ぶならこの時点で FXERD04 と決めます。そのコードで2025年9月を取ると、SURVEY_DATES は 20250901 から日付の配列になり、今回の取得では土日の値が null でした。営業日にだけ値が入る系列なので、休日はデータがない時期として null になるとみられます。
企業物価指数のほうは、PR01 の PRCG20_2200000000(国内の企業物価指数 総平均、2020年=100)を指定します。期種は月次で、startDate=202507&endDate=202509 なら SURVEY_DATES は 202507、202508、202509 の3件です。
取り違えを防ぐ確認手順
e-Statのような統計系APIと同じく、「取れた」と「正しいものが取れた」は別の話です。Claudeに取得させたあと、結果を報告させる前に次の確認を挟みます。
系列コードは名称と単位で突き合わせる
取得結果の NAME_OF_TIME_SERIES_J と UNIT_J を、依頼した内容と照らします。ドル円の日次を頼んだのに単位が 百万ドル なら、出来高の系列を引いています。FM08には、為替レートのほかにスポット出来高やスワップ出来高の系列も並んでいます。
期種と期間を取得後に検証させる
返ってきた FREQUENCY が想定の期種か、SURVEY_DATES の先頭と末尾が依頼した期間に収まっているかを確認させます。収録期間と合わない指定は、エラーにならず空で返ることがあります。指定した系列・時期がすべて収録期間外、または全系列のデータが欠損のときは、STATUSが200のまま M181030I(正常に終了しましたが、該当データはありませんでした)です。エラーにならないぶん、空のまま分析へ進みやすい箇所です。
欠損値の扱いを先に決める
為替の日次は、休日が null になります。そのまま平均を取ると、null を除く計算になるのか、0として入るのかが処理系で変わります。pandasで読み込む場合は、null を欠損のまま保持し、営業日だけにするのか、前の営業日の値で埋めるのかを、集計の前に決めます。扱いの詳しい書き方は、Claude Codeでpandasのデータ処理を書く記事が参考になります。
最終更新日を成果物に残す
出力の LAST_UPDATE は、系列のメタ情報やデータが更新されたときに変わります。成果物のCSVや集計表には、取得日時と一緒に残しておくと、あとから数値が食い違ったときに、改定か取り違えかを切り分けられます。
階層APIで一括取得する
DBの中の系列を丸ごと取りたいときは、階層APIが向いています。系列コードを並べる代わりに、DB内の階層構造(5階層の番号)で範囲を指定します。階層1は必須、階層2〜5は任意で、カンマ区切りです。* は「その階層をすべて」を意味します。
国際収支統計(BP01)の月次を、階層1〜3がすべて「1」の範囲で取る公式の例は次のとおりです。
https://www.stat-search.boj.or.jp/api/v1/getDataLayer?format=csv&db=BP01&frequency=M&startDate=202504&endDate=202509&layer=1,1,1階層APIは frequency が必須で、略称(M、Q など)で指定します。気をつけたいのは、系列数の数え方です。絞り込み条件に合う系列は、期種で絞る前に数えられます。そのため、指定した階層に月次と四半期が混ざっている場合、欲しいのは月次だけでも、四半期の系列まで1,250件の上限に含まれます。
階層APIの startPosition は、コードAPIと意味が違います。コードAPIでは指定したコードの並び順ですが、階層APIでは階層1〜5で並べたDB内の全系列に付いた順序番号を使います。絞り込んだ結果の何番目、ではありません。続きを取るときは、返ってきた NEXTPOSITION の値をそのまま渡します。
結果を公開するときの条件
取得した結果を使ったサービスを公開する場合、日本銀行は「API機能利用時の留意点」で次を求めています。
- サービスを公開したら、日本銀行の調査統計局に連絡する
- 次のクレジットを、利用者が見られる場所に表示する
このサービスは、日本銀行時系列統計データ検索サイトのAPI機能を使用しています。サービスの内容は日本銀行によって保証されたものではありません。
禁止されているのは、本機能の運用を妨害する行為と、短時間の高頻度アクセスです。違反または違反のおそれがあると判断された場合、利用が停止されることがあります。機能の停止や仕様変更は予告なく行われる場合があり、利用に伴う損害について日本銀行は責任を負わないと定められています。留意点自体も、事前の通知なしに変更される場合があります。
個人の分析にとどまる取得なら、公開の連絡もクレジットも関係しません。ブログやダッシュボードに数値を載せる段階になったら、この2点を足すだけで済みます。ほかの統計系APIの扱いは、e-Stat APIの記事やEDINET APIの記事と並べると違いが見えます。
エラーが出たときの読み方
エラー時は、CSVを指定していてもJSON形式で内容が返ります。まず STATUS と MESSAGEID を見ます。400はパラメータの誤りで、直してから再実行します。500と503は、時間をおいてやり直す種類です。
| MESSAGEID | 内容 | 対処 |
|---|---|---|
| M181001E | 内容Invalid input parameters | 対処使えない記号・全角文字、またはDB名付きのデータコードを直す |
| M181005E | 内容DB名が正しくありません | 対処DB名を確かめて直す |
| M181007E | 内容系列コードの数が1250を超えている | 対処系列を分けて取り直す |
| M181013E | 内容指定した系列コードは存在しない | 対処メタ情報で系列コードを確かめ直す |
| M181014E | 内容指定した系列コードの期種が一致しない | 対処同じ期種の系列ごとに分けて指定する |
| M181015E | 内容開始期の設定形式が期種と一致しない | 対処開始期の書式を期種に合わせる |
| M181090S | 内容予期しないエラー(500) | 対処時間をおいてやり直す |
| M181091S | 内容データベースアクセスエラー(503) | 対処時間をおいてやり直す |
M181014E と M181013E は、メッセージに「何番目のコードか」が出ます。Claudeにエラーを読ませるときは、番号をもとに該当コードをメタ情報へ戻って確認させると、修正が早くなります。
週次の系列にも癖があります。週次の期種には W0 から W6 の7種類があり、パラメータ設定時は全部 W と書きます。ただしコードAPIでは異なる曜日の週次を1回のリクエストに混ぜられず、W1 と W4 の系列を取るなら2回に分けます。
まとめ
日銀の時系列統計APIは、登録なしで使えるぶん、系列コードの確かめ方が成否を決めます。メタデータAPIで名称・単位・期種・収録期間を見てコードを選び、コードAPIで250件以内・同じ期種で取り、NEXTPOSITION が消えるまで間隔を空けて続けます。
Claude Codeには、コードを推測させない規約を CLAUDE.md に置き、実行を取得スクリプトに絞り、取得後に名称・単位・期種・期間を突き合わせさせます。止まらない取り違えを検証で止める、という組み方です。結果を外に出すときは、連絡とクレジット表示の2点が加わります。