いま5つの異なるサービスに EUR/USD のレートを聞けば、わずかに違う5つの数字が返ってきます。大きく違うわけではありません。ただ小数点以下4桁目、ときには3桁目が違う。チェックアウト画面が 1.0847 を表示していたのに銀行明細は 1.0821 だった、という理由で財務チームからチケットが上がった経験があるなら、これが机上の問題でないことはご存じでしょう。
では、為替レートAPIのデータはどこから来るのか。正直な答えは、どのAPIも為替レートを「知って」はいない、というものです。知るべき単一の為替レートなど存在しないからです。外国為替は中央取引所も大引けの鐘もない店頭市場であり、世界中で何千もの金融機関が互いに価格を提示し合っているだけです。あなたが呼び出せるAPIはすべて、その市場をサンプリングし、整形し、ひとつの数字として渡すパイプラインです。本記事ではそのパイプラインを層ごとに追い、二つの提供元が食い違う理由を正確に説明し、課金ロジックを載せる前にデータソースを検証する方法を示します。
短い答え:市場とあなたのJSONの間には3つの層がある
為替レートAPIは、無料でも有料でも、当社のものも含めて、同じ3層で構成されています。
- 取得。 生の価格が上流のソースから引かれます。機関投資家向けFXフィード、中央銀行の公表値、ブローカーや小売の気配値です。
- 正規化。 それらの生値が検証され、外れ値が除去され、複数ソースが混合され、通貨ペアごとに単一の参照レートが導出されます。
- 配信。 導出されたレートが一定の間隔でスナップショット化され、キャッシュされ、タイムスタンプ付きでHTTP経由で配信されます。
この3層のいずれかに差異があれば、レスポンスボディの数字は変わります。多くの開発者は食い違いが層1に起因すると考えますが、実際には層2と層3も同じくらい原因になっています。
層1 — 生の価格は実際どこから来るのか
インターバンクおよび機関投資家向けフィード
「本当の」為替レートに最も近いのはインターバンク市場、すなわち大手銀行と流動性供給者が互いに取引する価格です。これらの価格は、取引会場、プライムブローカー、マーケットデータベンダーから、bid と ask の連続的な気配値ストリームとして届きます。
この種のフィードは入手可能な中で最も忠実度が高い一方、最も高価でもあります。無料APIがこれを一次ソースとして使うことがほとんどない主因はそこにあります。提供元が「リアルタイム」や「1分未満」の更新をうたう場合、ほぼ必ずパイプラインの最上流に機関投資家向けフィードが置かれています。
インターバンクフィードが返すのは1つではなく2つの価格、bid と ask であることに注意してください。APIレスポンスに現れる単一のレートは通常その中間値です。この区別に馴染みがなければ、外国為替における bid-ask スプレッドの解説をご覧ください。
中央銀行の参照レート
第二の大きなソースは中央銀行の公式公表値です。最も有名な例は欧州中央銀行で、欧州各国中銀による協議手続きに基づき、TARGET営業日ごとに16:00 CET前後にユーロ参照為替レートを公表しています。他にも数十の中央銀行が自国通貨について同等の日次レートを公表しています。
中銀レートには2つの大きな利点があります。無料であること、そして権威があることです。多くの税務当局や会計基準が報告目的での使用を明示的に認めています。無料API エコシステムの大部分がこれを土台にしているのはそのためです。この分野で広く使われているオープンソースプロジェクト Frankfurter は、84の中央銀行から201通貨の日次レートを追跡し、履歴は1948年まで遡ります。いずれも公開データの再配布です。
一方で、深刻な制約も2つあります。
- 日次のスナップショットであり、ライブ価格ではありません。 16:00 CET の参照レートは、09:00 や 22:00 に何が起きたかを何も語りません。
- 週末と祝日には止まります。 APIが土曜日のデータを返さない、あるいは金曜の数字を繰り返す場合、ECB由来のソースであることが通常の説明です。
小売・ブローカーの気配値
第三のソースは最終顧客向けの価格設定です。銀行、カードネットワーク、決済事業者、送金サービスが実際に顧客へ提示する値です。これらのレートにはすでにマークアップ、つまり市場レートの上に載せられた利幅が含まれています。
消費者向け比較サイトで見たレートが銀行明細と一致しないのはこのためです。どちらが間違っているわけでもなく、測っているものが違うのです。消費者向けサイトが通常示すのはミッドマーケットレートであり、銀行が提示するのはミッドマーケットレートに自社スプレッドを加えたものです。多くのソフトウェア用途では、ミッドマーケットの数字を取得し、自社のマークアップは見える形・監査できる形で明示的に適用するのが正解です。
層2 — 提供元はフィードをどう単一レートに変えるのか
生の価格が届いたら、提供元はどの数字を公表するか決めなければなりません。ここで4つの判断が行われ、そのすべてが提供元同士の分岐点になります。
ブレンディング。 商用APIの多くは単一の上流ソースに依存しません。たとえば Open Exchange Rates は、自社データを複数の提供元から収集しアルゴリズムでブレンドしたものと説明しています。ブレンドは単発の異常ティックをならしますが、その重み付けは非公開です。二つのブレンド済みフィードが完全一致しないのはまさにこのためです。
外れ値の除去。 ある会場からの誤った気配値は桁違いにずれることがあります。提供元はコンセンサス周辺の許容帯から外れた価格を捨てるフィルタをかけます。積極的なフィルタリングはレートを安定させますが、本物の値動きへの反応は鈍くなります。緩いフィルタリングは反応が速い代わりに時折ノイズが混じります。
中間値の導出。 上流フィードが bid/ask なら、提供元は中間値を公表します。単純中点 (bid + ask) / 2 が標準ですが、出来高加重のアプローチではわずかに異なる結果になります。
クロスレートの三角計算。 3万を超える通貨ペア全部を直接調達している提供元はありません。ほとんどのペアは基軸通貨(通常は USD か EUR)を経由して計算されます。
GBP/JPY = (USD/JPY) / (USD/GBP)つまりエキゾチックペアのレートは、別の2ペアの丸めとタイミングを引き継ぎます。USD を軸にする提供元と EUR を軸にする提供元では、同じクロスでも数字が変わります。仕組みはクロスレート解説で扱っています。
層3 — レートがあなたのコードに届くまで
最後の層は、開発者が最も制御でき、最も意識しない層です。
更新頻度は提供元間・料金プラン間で最大の差別化要因です。無料プランは一般に1日1〜2回更新します。有料プランは1時間ごと、10分ごと、あるいは60秒ごとです。同一データを使う2つのAPIでも、一方が14:00に、他方が14:47にスナップショットを取れば、それだけで食い違います。
キャッシュはこれを増幅します。ほとんどのAPIはCDNの背後にあり、よくできたクライアントはさらにその上でローカルにキャッシュします。10分更新に15分のエッジキャッシュを重ねれば、アプリは25分前のレートで動いている可能性があります。価格表示なら問題ありませんが、取引を決済するには許容できません。実務上の問いは常にこの操作にとって、どれだけ古ければ古すぎるのかです。通貨APIのキャッシュとエラーハンドリングのガイドで、その窓幅の決め方を解説しています。
タイムスタンプが防御線です。まともなAPIはレートを取得した時刻を必ず返します。それを読んでください。レスポンスを受け取った瞬間が、そのレートが有効だった瞬間だと決めつけないでください。
const MAX_AGE_SECONDS = 900; // 15 minutes
async function getRate(base, symbol) {
const res = await fetch(
`https://api.finexly.com/v1/latest?base=${base}&symbols=${symbol}`,
{ headers: { Authorization: `Bearer ${process.env.FINEXLY_API_KEY}` } }
);
const data = await res.json();
const ageSeconds = Math.floor(Date.now() / 1000) - data.timestamp;
if (ageSeconds > MAX_AGE_SECONDS) {
throw new Error(`Rate is ${ageSeconds}s old — refusing to price on stale data`);
}
return { rate: data.rates[symbol], ageSeconds };
}こちらが基礎となるリクエストと、代表的なレスポンス構造です。
curl "https://api.finexly.com/v1/latest?base=USD&symbols=EUR,GBP,JPY" \
-H "Authorization: Bearer YOUR_API_KEY"{
"success": true,
"base": "USD",
"timestamp": 1755244800,
"rates": {
"EUR": 0.9241,
"GBP": 0.7863,
"JPY": 147.2150
}
}パラメータとエンドポイントの詳細は Finexly APIドキュメント にあります。
なぜ2つのAPIが同じペアで違う数字を返すのか
3つの層を合わせると、食い違いの原因は6つ。おおむね実害の大きい順に並べます。
- スナップショット時刻の違い。 圧倒的に多い原因です。どちらのフィードも壊れておらず、見た瞬間が違うだけです。
- ソース構成の違い。 中銀由来のレートとインターバンク由来のレートは、定義上まったく別物を測っています。
- ミッドマーケット対マークアップ込み。 一方は市場の中間値を、他方はスプレッドを内包した顧客向け価格を返します。
- クロスの基軸通貨の違い。 USD 経由と EUR 経由の三角計算は、同じ非USDペアでも異なる結果になります。
- 精度と丸め。 6桁を4桁に切り捨てる、あるいは逆ペアで公表されたものを再度逆数化する。いずれもズレを生みます。
- 忘れていたキャッシュ層。 CDN、フレームワークのHTTPキャッシュ、自前のRedis層がそれぞれ古さを積み上げます。
有用な目安として、主要ペアであれば信頼できるミッドマーケット系ソース2つの間で数ベーシスポイント(0.01% = 1bp)の差は正常かつ想定内です。50bp以上の差があれば、どちらかが古いか、マークアップ込みか、壊れています。出荷前にどちらかを突き止めるべきです。
信頼する前に為替レートAPIを検証する方法
提供元の精度に関する主張を鵜呑みにしないでください。財務チームが権威と見なすソースに対して、1週間この検査を回してみましょう。
import os
import requests
from datetime import datetime, timezone
FINEXLY_URL = "https://api.finexly.com/v1/latest"
HEADERS = {"Authorization": f"Bearer {os.environ['FINEXLY_API_KEY']}"}
def get_rate(base: str, symbol: str) -> dict:
r = requests.get(
FINEXLY_URL,
headers=HEADERS,
params={"base": base, "symbols": symbol},
timeout=5,
)
r.raise_for_status()
data = r.json()
return {
"rate": data["rates"][symbol],
"captured_at": datetime.fromtimestamp(data["timestamp"], tz=timezone.utc),
}
def basis_points(a: float, b: float) -> float:
"""Difference between two rates, in basis points."""
return abs(a - b) / ((a + b) / 2) * 10_000
primary = get_rate("EUR", "USD")
reference = 1.0839 # whatever your accounting source published
diff = basis_points(primary["rate"], reference)
print(f"Finexly: {primary['rate']} captured {primary['captured_at']:%H:%M UTC}")
print(f"Reference: {reference}")
print(f"Delta: {diff:.1f} bp -> {'OK' if diff < 25 else 'INVESTIGATE'}")結果で見るべき点は3つです。
- 差は安定しているか、ドリフトしているか。 一定のオフセットは体系的なマークアップを示唆します。ランダムならタイミングの問題です。
- 特定の時間帯に差が跳ねるか。 それはスナップショット時刻、多くは中央銀行の公表ウィンドウ周辺を指しています。
- 週末はどうなるか。 金曜午後に凍結し月曜に再開するなら中銀由来です。月曜の照合作業をそれに合わせて設計してください。
三角計算の健全性も確認できます。クロスを直接取得し、USD 経由でも計算してみる。両者は1〜2ベーシスポイント以内で一致するはずです。
用途に応じたデータソースの選び方
普遍的に「最良」のソースはありません。あるのは、いま作っているものにとって正しいソースだけです。
| 用途 | 必要なもの | 許容される古さ |
|---|---|---|
| 購入者への価格表示 | ミッドマーケットレート+自社マークアップ | 時間単位 |
| SaaSのサブスク課金 | ミッドマーケット、請求処理ごとに1スナップショット、請求書と共に保存 | 時間単位、ただし記録必須 |
| 会計・税務報告 | 当該日付の中銀参照レート | 定義上、日次 |
| 分析・ダッシュボード | 単一ソースからの一貫した時系列 | 日次 |
| 送金・ペイアウト | 明示的な許容帯を伴う新しいミッドマーケット | 分単位 |
| トレーディング・ヘッジ | 機関投資家向けフィードの実 bid/ask | 秒単位 |
まだ検討段階であれば、無料と有料の通貨API比較でプランを上げると何が変わるかを整理しています。料金プランページでは更新頻度とリクエスト上限の位置づけを確認できます。任意のペアを手早く目視確認したい場合、通貨コンバーターはAPIと同じ基盤フィードを使っています。
よくある質問
無料の通貨APIはデータをどこから取得していますか?
ほぼ常に中央銀行の公表値、最も多いのは欧州中央銀行の日次ユーロ参照レートで、他の公開ソースといくつか混合される場合もあります。無料プランが通常1日1回更新、週末はスキップ、有料より対応通貨が少ないのはこのためです。
なぜ私のAPIの為替レートは Google と違うのですか?
Google が表示するのはミッドマーケットの参照レートで、連続的なライブ価格ではなくスナップショットです。あなたのAPI呼び出しと同じ瞬間にサンプリングされているとは限りません。小さな差は正常です。大きな差は通常、どちらかがミッドマーケットではなくマークアップ込みの小売レートであることを意味します。
会計・税務報告にはどの為替レートを使うべきですか?
取引日について所管の中央銀行が公表した公式参照レートを使ってください。多くの税務当局が期待するのはこれです。ライブレートを流用せず、日付を明示した履歴エンドポイントから取得し、取引レコードと一緒に保存してください。
リアルタイム為替APIは本当にリアルタイムですか?
文字どおりの意味ではまれです。「リアルタイム」は通常、提供元が短い間隔で更新することを意味し、最上位プランでは60秒が一般的です。ティックごとに配信するという意味ではありません。マーケティング文言ではなく、レスポンスのタイムスタンプと文書化された更新間隔を確認してください。
APIを使わずに為替レートをスクレイピングしてもよいですか?
可能ですが、スクレイピング先ページのあらゆる障害モードを引き受けることになります。レイアウト変更、レート制限、タイムスタンプなし、履歴の遡及取得なし、そして多くの場合は利用規約違反です。全体のトレードオフは通貨API対Webスクレイピングで扱いました。
検証できるフィードの上に構築する
為替データの出所を把握しているかどうかは、一文で説明できる通貨バグと、エンジニアリング1週間を食い潰すバグとの分かれ目です。統合前にどの提供元にも3つ質問してください。ソースは何か、更新頻度はどれくらいか、すべてのレスポンスに取得タイムスタンプが付くか。
本当に検証できる為替レートを組み込む準備はできましたか。Finexly の無料APIキーを取得。クレジットカードは不要です。170を超える通貨に対して月1,000リクエストの無料枠から始められ、初日からタイムスタンプ付きレスポンスと履歴データが使えます。
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →