マルチカレンシー対応のシステムは、いずれ必ず会計士と対面します。そして一見些細に聞こえて実はまったく些細でない質問を受けます。「この請求書、どのレートを使いましたか?」 もし正直な答えが「その日の午後に API が返した値です。保存はしていません」なのであれば、それはどれだけコードを綺麗に書いても申告時には解決しない問題です。
税務申告のための為替レートを正しく扱ううえで重要なのは、正しいレートを選ぶことではありません(多くの当局はその点について意外なほど寛容です)。むしろ何年も後になってから、どのレートを使い、それがどこから来て、同じ期間の他のすべての取引にも同じルールを適用したことを証明できるかどうかです。これはデータモデリングの問題であり、そして誰も書かない部分でもあります。
本ガイドでは、IRS、HMRC、EU VAT 指令が実際に求めている内容、修正再表示につながる 5 つの換算バグ、そして今週から実装できるレートスナップショットのスキーマを扱います。
「その」為替レートについて誰も合意していない——そこが肝心
この分野全体で最も有用な一文は、IRS 自身のものです。
「内国歳入庁には公式の為替レートは存在しません。一般に、一貫して使用されている公表レートであればいずれも受け入れられます。」
2 回読んでください。ほぼすべての法域で同じ構造が現れるからです。義務とされるのはこの特定の数値を使うことであることはまれで、擁護できるソースを使い、それを一貫して使うことなのです。一貫性はレートプロバイダの性質ではなく、あなたのシステムの性質です。週末になるとコードが黙って別のソースにフォールバックするなら、誤った数値を一度も取得していなくても、要件はすでに破られています。
米国:原則はスポット、譲歩としての年間平均レート
IRS の基準はスポットレートです。「原則として、その項目を受領、支払、または発生させた時点で通用しているレート(すなわちスポットレート)を使用してください。」 給与、賃料、継続的な事業収益のように収入が平準的に発生する場合、IRS は年間平均為替レート表を公表し、申告者に対して「外貨建金額を該当する年間平均為替レートで除してください」と指示しています。同ページの最終更新である 2026 年 2 月 24 日時点で、この表は 2021 年から 2025 年までの課税年度をカバーしています。
この演算の向きに注意してください。IRS の表は 1 米ドルあたりの外貨単位数で表示されているため、除算します。誤って逆にすると、少しずれるどころか、レートの2 乗だけ誤ります。円建ての金額なら、およそ 4 桁の違いです。レートの向きについては後述します。この領域で最も頻出する単一の統合バグだからです。
米国連邦機関向けの報告には、もう 1 つ公式なシリーズがあります。Treasury Reporting Rates of Exchange で、FiscalData.Treasury.gov にて 四半期ごとに CSV、JSON、XML で公表されます。財務省はこれを「公表される報告書の日付の前月末営業日時点で、各在外公館の支出官が報告した、米国政府が公的支出のために外貨を取得しうるレートを反映したもの」と説明しています。実勢レートが公表レートから 10% 以上乖離した場合、財務省は四半期の途中で改訂を発行します。Fiscal Data API はオープンで、アカウントもトークンも不要です。政府由来の参照シリーズと照合したい場合には知っておく価値があります。
英国:VAT Notice 700 §7.6 は法的効力を持つ
英国はより規範的で、該当する文言は 1994 年 VAT 法 附則 6 第 11 項に基づき法的効力を持ちます。VAT Notice 700 は、外貨建の供給をポンドに換算するための 3 つの経路を事業者に示しています。
- 供給時点における英国市場の売却レート。 これがデフォルトです。同 Notice は「全国紙に掲載されたレートは、当該時点のレートの証拠として認められます」と述べています。
- HMRC の期間レート(HMRC period rate of exchange)。関税目的で公表されるものです。「すべての供給について、または特定の種類もしくは記述の供給すべてについて」採用できます。事前の届出は不要ですが、「いったんこの選択を行った場合、VAT Written Enquiries Team に書面で申し出て同意を得ない限り、これを変更することはできません」。
- 独自の商業レートまたは方法。これには書面による申請が必要です。HMRC は、そのレートが「英国通貨市場を参照して決定されている」か、「客観的に検証可能」か、更新頻度はどの程度かを評価します。決定的なのは「先物レート、または先物レートから導出される方法は認められません」という点で、これはスポットレートとフォワードレートの違いと併せて理解しておくべき明確な境界線です。
そしてキャッシュ層を規律する一文がこれです。「いかなるレートまたは方法を採用する場合でも、ある供給に適用される適切なレートは、その供給の時点で通用しているものです。」 供給時点であって、請求書発行時点でも、支払時点でもなく、ましてやあなたの夜間バッチジョブの時点でもありません。
経路 2 を選ぶ場合、その仕組みは実に機械にやさしいものです。HMRC は月次レートを毎月最後から 2 番目の木曜日に公表します。これらは翌暦月に適用され、公表前日の正午時点のレートを表します。ファイルは予測可能な URL に置かれています。月がゼロ埋めされていない点に注意してください。
https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/monthly_csv_2026-9.csv
https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/monthly_xml_2026-9.xml月に 1 回取得してその月はキャッシュする。それだけで、その期間の英国 VAT 換算はすべて、調査官にそのまま手渡せるファイルから再現できます。
欧州連合:VAT 指令 第 91 条
EU 域内の供給について、理事会指令 2006/112/EC 第 91(2) 条は、「VAT の納税義務が発生した時点で、当該加盟国の最も代表的な 1 つまたは複数の為替市場において記録された直近の売却レート、または当該市場を参照して決定されるレート」と定めています。
27 の加盟国すべてでこれを実装するのは困難なため、指令は実務的な逃げ道を用意しています。加盟国は「代わりに、税の納税義務が発生した時点で欧州中央銀行が公表した直近の為替レートの使用を認めなければならない」とされています。ユーロ以外の 2 通貨間の換算は「各通貨のユーロ為替レートを用いて」行います。つまり、通貨ペアを直接建値するのではなく EUR を経由してクロスさせるということです。加盟国は、この選択肢を行使している旨の届出を求めることができます。
輸入については、第 91(1) 条は代わりに関税評価額の算定に関する関税規則に委ねています。同じ帳簿の中に、まったく異なる日付の、まったく異なるレートが存在するのです。「EU VAT」を 1 つの換算ルールとして扱っているシステムは、その時点ですでに誤っています。
すべての土台にあるもの:IAS 21
税務ルールは会計方針の上に載っており、IFRS 適用企業にとってその方針とは IAS 21 です。主に 4 つの規定が働きます。
- 外貨建取引は、当初認識時に取引日のスポットレートで認識されます(IAS 21.21)。
- 簡便法として平均レートが認められますが、それは「為替レートが著しく変動しない限り」のことです(IAS 21.22)。これはデフォルトではなく条件であり、変動の激しい四半期に静かに破綻するのがまさにこの条項です。
- 貨幣性項目は報告日に決算日レートで再換算されます(IAS 21.23)。
- 取得原価で測定される非貨幣性項目は取引日レートのまま据え置かれ、再換算されません。
米国会計基準も ASC 830 の下でおおむね同様の結論に至ります。開発者にとっての実務的な帰結は、1 つの取引がそのライフサイクルを通じて2 つないし 3 つの異なるレートを正当に必要としうるということです。認識時に 1 つ、期末に 1 つ、決済時に 1 つ。スキーマにはそのすべてを収める余地が必要です。そこから生じる損益が商業的に何を意味するかについては、事業者のための為替リスク管理ガイドで扱っています。
修正再表示につながる 5 つの換算バグ
1. レートの向き
base=USD&symbols=EUR は 1 ドルあたりのユーロを返します。base=EUR&symbols=USD は 1 ユーロあたりのドルを返します。IRS の年間表は 1 米ドルあたりの外貨なので除算し、base=EUR の Finexly レスポンスは 1 ユーロあたりの米ドルなので乗算します。どちらも正しく、混同することだけが誤りです。
対処法は地味ですが効果的です。列に rate という名前を絶対に付けないこと。quote_per_base と名付け、向きをコメントではなくスキーマ上で一義的にしてください。
2. リプレイではなく再クエリ
2029 年の監査が 2026 年の取引について尋ねてきます。レポート生成時にレポーティングのコードがライブ endpoint を呼んでいるなら、同じレポートを 2 回実行すれば 2 つの異なる数値が出ます。ある取引に適用されたレートは、ルックアップではなくその取引に関する事実です。換算したその瞬間に永続化してください。ヒストリカル endpoint はバックフィルと照合のために存在するのであって、保存の代わりではありません。バックフィルのパターンについてはヒストリカル為替レート API ガイドをご覧ください。
3. スポットが必要な場面での平均レート
月次平均は便利で、認められることも多いのですが、IAS 21.22 には条件が付いており、単発の取引は IRS のガイダンス上、原則として取引日レートを要します。方法をレートと並べて保存しておけば、「なぜこの数値なのか?」に発掘作業なしで答えられます。
4. 欠落する日付
週末、国民の祝日、TARGET 非稼働日には公表レートが存在しません。どのシステムにも明示的なルール(通常は「当該日以前の直近公表レート」)が必要であり、さらにどのルールが発動したかを記録する必要があります。半年後には、静かなフォールバックとバグは見分けがつきません。これはキャッシュとエラーハンドリングの実践と直接重なります。
5. 精度と丸め
表示する桁数より多くの小数位を保存し、丸めは最終的な表示または計上のステップでちょうど 1 回だけ行ってください。数千件の請求書にわたって中間ステップごとに丸めると、説明が面倒で元に戻すことも不可能な照合差異が生まれます。その算術については通貨の丸めと小数位で詳しく解説しました。
設計すべきはレートのルックアップではなくレートのスナップショット
換算を関数呼び出しとして考えるのをやめ、不変のレコードとして考え始めた瞬間に、この問題全体が崩れ落ちます。以下は、ここまでに述べたすべての要件を満たす最小限のスキーマです。
CREATE TABLE fx_rate_snapshot (
id BIGSERIAL PRIMARY KEY,
transaction_id BIGINT NOT NULL,
-- direction is in the name, not in a comment
base_currency CHAR(3) NOT NULL, -- e.g. 'EUR'
quote_currency CHAR(3) NOT NULL, -- e.g. 'USD'
quote_per_base NUMERIC(20,10) NOT NULL,
rate_date DATE NOT NULL, -- the date the rate APPLIES to
method TEXT NOT NULL, -- 'spot' | 'monthly_period' | 'yearly_average'
fallback_applied TEXT, -- 'previous_business_day' | NULL
source TEXT NOT NULL, -- 'finexly' | 'hmrc_monthly' | 'irs_yearly'
source_reference TEXT, -- file name, request id, or table year
retrieved_at TIMESTAMPTZ NOT NULL, -- when WE obtained it
amount_base NUMERIC(20,4) NOT NULL,
amount_quote NUMERIC(20,4) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- one authoritative conversion per transaction per purpose
CREATE UNIQUE INDEX ux_fx_snapshot_txn_method
ON fx_rate_snapshot (transaction_id, method, rate_date);監査上の重みの大半は 3 つの列が担っています。rate_date はそのレートが適用される日付であり、取得した瞬間を表す retrieved_at とは意図的に分離されています。9 月のバックフィル中に取得した 3 月 13 日のレートはまったく正当であり、この 2 つの timestamp の組がそれを率直に物語ります。fallback_applied は、週末ルールを目に見えない挙動から記録された証拠へと変えます。
行が更新されることは決してない点に注意してください。レートが訂正された場合は、新しい行を挿入して古い行を置き換えます。編集できる監査証跡は、監査証跡ではありません。
擁護できるヒストリカルレートの取得
取引日のレートが必要な場合は、現在のレートではなく特定の日付をリクエストします。
curl "https://api.finexly.com/v1/historical?date=2026-03-13&base=EUR&symbols=USD" \
-H "Authorization: Bearer YOUR_API_KEY"{
"base": "EUR",
"date": "2026-03-13",
"rates": {
"USD": 1.0842
}
}base=EUR の場合、この値は 1 ユーロあたりのドルです。したがって €10,000 の請求書は乗算により $10,842.00 に換算されます。以下は Python での書き込み時スナップショットのパターンで、欠落日のフォールバックと上記スキーマが要求するフィールドを含みます。
import requests
from datetime import date, timedelta
from decimal import Decimal, ROUND_HALF_UP
API = "https://api.finexly.com/v1/historical"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
def fetch_rate(base: str, quote: str, on: date, max_lookback: int = 5):
"""Return (quote_per_base, rate_date, fallback) for a given date.
Walks back to the most recent published rate if `on` is a weekend
or a market holiday, and reports which day it actually landed on.
"""
for offset in range(max_lookback + 1):
d = on - timedelta(days=offset)
r = requests.get(
API,
params={"date": d.isoformat(), "base": base, "symbols": quote},
headers=HEADERS,
timeout=10,
)
r.raise_for_status()
rates = r.json().get("rates", {})
if quote in rates:
fallback = "previous_business_day" if offset else None
return Decimal(str(rates[quote])), d, fallback
raise LookupError(f"No {base}/{quote} rate within {max_lookback} days of {on}")
def convert_for_filing(amount_base, base, quote, transaction_date):
"""Convert once, and return everything an auditor will ask for."""
rate, rate_date, fallback = fetch_rate(base, quote, transaction_date)
amount = Decimal(str(amount_base))
converted = (amount * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
return {
"base_currency": base,
"quote_currency": quote,
"quote_per_base": rate,
"rate_date": rate_date.isoformat(),
"method": "spot",
"fallback_applied": fallback,
"source": "finexly",
"amount_base": amount,
"amount_quote": converted,
}
snapshot = convert_for_filing(10000, "EUR", "USD", date(2026, 3, 13))
print(snapshot["amount_quote"], snapshot["rate_date"], snapshot["fallback_applied"])
# -> 10842.00 2026-03-13 Noneこの関数は、換算と同時に記録も済ませます。永続化層が何であれ、下流の何かがその数値を目にする前に、この辞書を書き込んでください。同じ規律はマルチカレンシー請求、SaaS 課金、国際給与計算のいずれでも報われます。それらはすべて、最終的に同じ税務申告書に行き着くのですから。
公式の公表レートとの照合
経路 2 に基づく英国 VAT では、HMRC の月次ファイルを月に 1 回取得し、その期間における信頼できる情報源として保存します。
import csv, io, requests
from datetime import date
def hmrc_monthly_rates(year: int, month: int) -> dict:
"""HMRC monthly rates for VAT/customs. Note: month is NOT zero-padded."""
url = (
"https://www.trade-tariff.service.gov.uk/exchange_rates/view/files/"
f"monthly_csv_{year}-{month}.csv"
)
resp = requests.get(url, timeout=15)
resp.raise_for_status()
reader = csv.DictReader(io.StringIO(resp.text))
# Don't hard-code the header text: find the ISO-4217 code column by shape.
code_col = next(
c for c in reader.fieldnames if "code" in c.strip().lower()
)
return {
row[code_col].strip(): row
for row in reader
if row.get(code_col) and len(row[code_col].strip()) == 3
}そのうえで定期的な乖離チェックを走らせます。保存済みの各スナップショットをその期間の公式レートと比較し、意図して定めた許容範囲を外れるものにフラグを立てるのです。市場レートと公表された行政レートの間に小さな乖離が生じるのは想定内で、通常は許容されます。ただし、調査官が計算してみせる前に、その差の大きさを自分で知っておきたいものです。これを総勘定元帳に組み込むのであれば、会計ソフトとの連携および為替レート API はどこからデータを取得しているのかに関する解説が、次に出てくる出所の問題をカバーしています。
マルチカレンシーデータの申告前チェックリスト
- 換算後の金額にはすべて保存済みのレートがある。 実行時にヒストリカル換算を再計算するレポートは存在しない。
- レートの向きが一義的である——ドキュメントではなく列名において。
rate_dateとretrieved_atは別々のフィールドであり、両方に値が入っている。- 欠落日のルールが明示され、記録されている——暗黙のリトライではなく。
- 取引の種類ごとに 1 つの方法を、期間全体にわたって一貫して適用する——これは米国でも英国でも実際の法的要件である。
- 丸めは 1 回だけ、最終ステップで、文書化されたモードで行う。
- スナップショットの行は追記のみ。 訂正は置き換えであり、上書きではない。
この 7 つをやり切れば、会計士の質問はもう怖くなくなります。答えはクエリになるのです。
よくある質問
IRS は税務申告にどの為替レートを要求しますか? 特定のものはありません。IRS は自らに「公式の為替レートは存在しない」と明言し、「一貫して使用されている公表レートであれば一般に受け入れる」としています。デフォルトは、その項目を受領、支払、または発生させた時点で通用しているスポットレートです。平準的に発生する収入については、IRS が年間平均レート表を公表し、外貨建金額を掲載レートで除するよう申告者に指示しています。
VAT について、HMRC の公表レートの代わりに通貨 API を使えますか? 使えますが、限度があります。VAT Notice 700 §7.6 は供給時点の英国市場売却レートをデフォルトとしているため、一貫して適用する限り、市場ベースの API レートはこの経路に適合します。HMRC 自身の期間レートは事前の届出なしに採用できる明示的な代替手段ですが、いったん採用すると書面による同意なしに戻すことはできません。この 2 つの経路のいずれにも当てはまらないレートや方法には書面による申請が必要で、先物レートは認められません。
為替レートは保存する必要がありますか、それとも後で引き直せばよいですか? 保存してください。保存されたレートは換算を再現可能にします。再クエリはそれを新たな計算に変えてしまい、すでに提出した申告書と一致しないおそれがあります。レート、その日付、その出所、そして取得した瞬間を保存することこそが、数値を証拠に変えるのです。
週末や祝日が取引日の場合、どのレートを使うべきですか? 非取引日には公表レートがないため、明示されたルールが必要です。最も一般的なのは取引日以前の直近公表レートです。どのルールを選ぶかより重要なのは、それが文書化され、一律に適用され、影響を受ける各行に記録されていることです。
税務目的では小数点以下何桁を保存すべきですか? プロバイダが返す精度をそのまま保存し(小数 6〜10 桁が妥当な列幅です)、計上時または表示時にのみ丸めてください。早い段階で繰り返し丸めることが、誰も追跡できない照合差異の典型的な原因です。
ECB のレートは EU VAT の要件を満たしますか? VAT 指令 第 91(2) 条は、税の納税義務が発生した時点で公表された直近の ECB レートを加盟国が受け入れることを義務付けており、異なる通貨間の換算は各通貨のユーロレートを経由して行います。一部の加盟国はこの選択肢を利用している旨の届出を求めており、輸入については代わりに関税評価のルールが適用されます。
レートを監査に耐えるものに
リアルタイムおよびヒストリカルの為替レートをプロジェクトに組み込む準備はできましたか?無料の Finexly API キーを取得——クレジットカードは不要です。月あたり 1,000 リクエストの無料枠から始めて、成長に合わせてアップグレードできます。ヒストリカル endpoint の完全なリファレンスは API ドキュメントを、単発の確認には通貨コンバーターを、プロバイダを比較検討中なら通貨 API の比較を、レポーティング量が増えてきたら料金プランをご覧ください。
本記事はマルチカレンシー対応システムを構築する開発者向けの技術ガイドです。税務上の助言ではありません——申告を行う各法域において、有資格のアドバイザーに換算方針を確認してください。
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 →