Google Sheets でライブ為替レートを取得する方法(GOOGLEFINANCE、Apps Script、通貨 API)
Google Sheets でライブ為替レートを取得するのは、すでに解決済みの問題に見えます。=GOOGLEFINANCE("CURRENCY:USDEUR") と入力すれば数値が表示され、それで終わりです。個人の旅行予算なら、それで十分に用は足ります。ところが、そのスプレッドシートが請求書、給与計算、売上レポート、あるいは同僚が判断材料にする何かに接続された瞬間に、それは通用しなくなります。ライセンス上の制限、ドキュメント化された日付の癖、そしてほとんどのチュートリアルが触れない Apps Script の制約があるからです。
本ガイドでは、実用的な 3 つの方法をすべて取り上げます。組み込みの GOOGLEFINANCE 関数、通貨 API を背後に置いた Apps Script のカスタム関数、そして時間主導型トリガーで更新されるスケジュール実行のレート表です。実際のクォータの数値、Google 自身の注意書きの正確な文言、そして実行可能なコードを添えて解説します。以下に登場する Google の挙動に関する記述はすべて Google 自身のドキュメントからの引用であり、ドキュメント化されていない主張にはその旨を明記しています。
Google Sheets に為替レートを取り込む 3 つの方法
GOOGLEFINANCE | Apps Script のカスタム関数 | スケジュール実行のレート表 | |
|---|---|---|---|
| セットアップ時間 | 数秒 | 約 10 分 | 約 20 分 |
| API キーの要否 | 不要 | 必要 | 必要 |
| 更新 | 自動(再計算時) | 再計算時 | 自分で制御するトリガー |
| ヒストリカルレート | あり(ただし注意点あり) | プランによる | あり |
| Apps Script / Sheets API での動作 | ヒストリカル: 不可 | 可 | 可 |
| 商用 / 業務利用 | Google の利用規約により制限あり | API プロバイダの規約に従う | API プロバイダの規約に従う |
| 最適な用途 | ちょっとした参照、個人用シート | 単発の換算列 | 他人が依存するもの全般 |
方法 1: GOOGLEFINANCE — Google が実際に述べていること
基本の通貨数式
どのチュートリアルでも教わるパターンは、2 つの ISO 4217 通貨コードを連結した CURRENCY: ティッカーです。
=GOOGLEFINANCE("CURRENCY:USDEUR")セル A2 の金額を換算するには:
=A2 * GOOGLEFINANCE("CURRENCY:USDEUR")通貨コードを保持した 2 つのセルからペアを組み立てるには:
=GOOGLEFINANCE("CURRENCY:" & B2 & C2)競合記事がどこも書かない、正直な注意点: CURRENCY:XXXYYY というティッカー形式は、Google の公式 GOOGLEFINANCE ドキュメントのどこにも登場しません。ドキュメント化されたシグネチャは GOOGLEFINANCE(ticker, [attribute], [start_date], [end_date|num_days], [interval]) であり、ヘルプページにある通貨関連の記載は "currency" 属性(証券の価格表示通貨)とチャートの例だけです。CURRENCY: のペア構文は動作しますし何年も動き続けていますが、それはコミュニティが確立した挙動であって、ドキュメント化された契約ではありません。つまり Google は廃止予告なしにこれを変更できます。さらに Google は対応通貨ペアの一覧を一切公開していません。したがって「約 50 通貨に対応」などと書いている記事は、単なる当て推量です。
ヒストリカルレート: 誰もが間違える属性のルール
日付を渡すとヒストリカルデータが返ります。
=GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,15))=GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,1), DATE(2026,1,31), "DAILY")属性に注目してください。Google は明確にこう記しています。「日付パラメータが指定された場合、そのリクエストはヒストリカルとみなされ、ヒストリカル属性のみが使用できます」。ヒストリカル属性は open、close、high、low、volume、all であり、"price" はそこに含まれません。"price" はリアルタイム専用の属性としてドキュメント化されています(「リアルタイムの相場。最大 20 分遅延」)。
いま上位表示されている Google Sheets の通貨チュートリアルを見てみてください。その多くが GOOGLEFINANCE("CURRENCY:USDEUR", "price", DATE(...)) を提示しています。この組み合わせは Google 自身のドキュメントと矛盾します。"close" を使ってください。
もう 2 つ、身につけておく価値のあるドキュメント化された挙動があります。
- 「
start_dateが指定され、end_date|num_daysが指定されていない場合、その 1 日分のデータのみが返されます」 - 「リアルタイムの結果は単一セル内の値として返されます。ヒストリカルデータは、たとえ 1 日分であっても、列見出し付きの展開された配列として返されます」 これこそが、正しく見えるヒストリカル数式が 2 列と見出し行をあなたの整ったレイアウトにこぼし出す理由であり、たいてい
INDEX(...,2,2)で包む必要がある理由です。
正午 UTC のずれ
これは日付を突き合わせるレポートを静かに壊します。Google の記述をそのまま引用します。
「Google は GOOGLEFINANCE に渡された日付を UTC 正午として扱います。それより前に取引を終える取引所では、1 日ずれる場合があります。」
各行がその計上日のレートを使わなければならない元帳の照合をしているなら、1 日のずれは丸め誤差ではなく本物の照合不一致です。それが自分のシートの話だと思うなら、こぼれ出た GOOGLEFINANCE の配列を監査記録として信頼する前に、為替レートと税務報告のガイドをお読みください。
遅延は 20 分ではなく 3 分
このテーマのほぼすべての記事が、GOOGLEFINANCE の為替レートは「最大 20 分遅延」だと書いています。この 20 分という数字は、"price" 属性に付いている証券相場の一般的な免責文言に由来します。Google 自身の Google Finance 免責事項ページには資産クラス別の遅延表が掲載されており、通貨の行は — グローバル、提供元は Morningstar — 3 分です。暗号資産も同じく 3 分です。
つまりデータはインターネットが信じているよりも新鮮です。Google が公開していないのは、Sheets がその数式をどのくらいの頻度で再計算するかであり、実際に気にすべきなのはそちらの数字です。火曜日から再計算されていないセルに座っている 3 分前のレートは、依然として火曜日のレートです。具体的な再計算間隔を挙げている人がいれば、それは Google が一度もドキュメント化していないものを語っています。
比較として、Finexly はレートを 1 分ごとに更新し、リクエストに応じて返します。したがって鮮度は、スプレッドシートが再計算する気になったタイミングではなく、あなたが呼び出したタイミングの関数になります。プロバイダ全般で「ライブ」が何を意味するのかを理解したい場合は、為替レート API はどこからデータを取得しているのかをご覧ください。
誰も引用しない利用制限
これは本記事で最も重要な段落であり、上位表示されているチュートリアルのどれにも載っていません。Google の GOOGLEFINANCE ヘルプページから、そのまま引用します。
「利用制限: 本データは、金融業界の専門家による業務利用、または非金融企業(政府機関を含む)における他の専門職による業務利用を目的としたものではありません。業務利用の場合、サードパーティのデータプロバイダによる追加のライセンス料が発生することがあります。」
そして Google Finance の免責事項から:
「お客様は、事前の書面による同意を得ることなく、本サイトに掲載されたいかなるデータまたは情報も複製、改変、再フォーマット、ダウンロード、保存、再生産、再処理、送信、再配布せず、またそのようなデータや情報を商業的事業において使用しないことに同意するものとします。」
「Google は表示される為替レートの正確性を保証できません。為替レートの変動によって影響を受ける可能性のある取引を行う前に、現在のレートをご確認ください。」
これを、自分のシートが実際にやっていることと突き合わせてください。顧客向け請求書の金額を決める、経理チームのために仕入先請求書を換算する、換算後の売上高をクライアントに送るレポートへ書き出す — これらが「情報提供目的」だとは、とても言い切れません。ライセンス済みの為替レート API を使えばこの問いは丸ごと消えます。そして純粋な精度ではなく、まさにこの点こそが、財務チームが GOOGLEFINANCE から離れる本当の理由です。
そして決定的な壁
「ヒストリカルデータは Sheets API または Apps Script 経由でダウンロードまたはアクセスすることはできません。試みた場合、スプレッドシートの該当セルには値の代わりに #N/A エラーが表示されます。」
夜間エクスポート、Sheets API による取得、レートをスナップショットするスクリプト — 何かを自動化しようとした瞬間に、ヒストリカルな GOOGLEFINANCE データは設計上、選択肢から外れます。これこそが人々を方法 2 へ押しやる壁です。
方法 2: 通貨 API を背後に置いた Apps Script のカスタム関数
カスタム関数とは、Apps Script で書いた JavaScript の関数で、組み込み関数と同じようにセルから呼び出せるものです。Google はこれが Web リクエストと組み合わせて動作することを明言しています。カスタム関数は「個人データにアクセスしないサービスのみを呼び出せる」のであり、URL Fetch は許可リストに入っています。
ステップ 1: API キーを取得し、正しく保管する
Finexly ダッシュボードで無料キーを取得してください。月 1,000 リクエスト、クレジットカード不要です。そして、ここが肝心です。キーをハードコードしないでください。最もリンクされている Google Sheets の通貨チュートリアルのうち 2 本は、API キーをスクリプトに直接貼り付けています。そのファイルは、スプレッドシートを共有した相手全員のところへ一緒に付いていきます。
Apps Script エディタ(拡張機能 → Apps Script)で、次をエディタから一度だけ実行し、キーをスクリプト プロパティに保存します。
function storeApiKey() {
PropertiesService.getScriptProperties()
.setProperty('FINEXLY_API_KEY', 'YOUR_API_KEY');
}その後、ファイルからリテラルを削除してください。ドキュメント化された上限にも注意しましょう。プロパティ 1 件の値は 9 KB、プロパティ ストア全体で 500 KB が上限です。キーには十分すぎますが、データをキャッシュする場所ではありません。
ステップ 2: 単一ペア用のカスタム関数
/**
* Returns the live exchange rate for a currency pair.
*
* @param {string} from Base currency code, e.g. "USD".
* @param {string} to Quote currency code, e.g. "EUR".
* @return The exchange rate.
* @customfunction
*/
function FX_RATE(from, to) {
if (!from || !to) throw new Error('Both currency codes are required.');
var pair = String(from).toUpperCase() + '_' + String(to).toUpperCase();
var cache = CacheService.getScriptCache();
var hit = cache.get(pair);
if (hit !== null) return Number(hit);
var key = PropertiesService.getScriptProperties().getProperty('FINEXLY_API_KEY');
var res = UrlFetchApp.fetch(
'https://api.finexly.com/v1/rate?from=' + encodeURIComponent(from) +
'&to=' + encodeURIComponent(to),
{
headers: { Authorization: 'Bearer ' + key },
muteHttpExceptions: true
}
);
var code = res.getResponseCode();
var body = JSON.parse(res.getContentText());
if (code !== 200) {
throw new Error(body.error ? body.error.code + ': ' + body.error.message : 'HTTP ' + code);
}
cache.put(pair, String(body.rate), 300); // 5 minutes
return body.rate;
}セルでの使い方:
=FX_RATE("USD","EUR")
=A2 * FX_RATE($B$1, $C$1)/v1/rate エンドポイントは {"pair": "USD_EUR", "rate": 0.9215} を返します。パラメータの完全なリファレンスは Finexly API ドキュメントにあります。
ステップ 3: 範囲をまとめて処理する — 競合が例外なく見落とす部分
ここが失敗パターンです。Google はこれを直接ドキュメント化しています。
「スプレッドシートでカスタム関数が使われるたびに、Sheets は Apps Script サーバーへ個別の呼び出しを行います。スプレッドシートに数十(あるいは数百、数千!)のカスタム関数呼び出しが含まれている場合、この処理は遅くなることがあります。」
FX_RATE を 400 行分ドラッグすれば、400 回のラウンドトリップを発生させたことになります。カスタム関数には実行あたり 30 秒の制限があるため、API のクォータに達するはるか手前で Exceeded maximum execution time (line 0). という注記付きの #ERROR! に突き当たります。
Google が推奨する解決策は配列でのバッチ処理です。範囲を受け取り、配列を返す。Finexly の /v1/convert エンドポイントはカンマ区切りのペアを受け付けるので、列全体が 1 回の HTTP リクエストになります。
/**
* Converts a column of amounts from one currency to another in a single API call.
*
* @param {A2:A400} amounts Range of amounts.
* @param {string} from Base currency code.
* @param {string} to Quote currency code.
* @return {Array} Converted amounts.
* @customfunction
*/
function FX_CONVERT_RANGE(amounts, from, to) {
var rate = FX_RATE(from, to); // one fetch, then cached
var rows = Array.isArray(amounts) ? amounts : [[amounts]];
return rows.map(function (row) {
return row.map(function (v) {
return (v === '' || v === null) ? '' : Number(v) * rate;
});
});
}=FX_CONVERT_RANGE(A2:A400, "USD", "EUR")数式は 1 つ、ネットワーク呼び出しも 1 回、ラウンドトリップは 399 回削減。複数ペアが同時に必要なら、/v1/convert?q=USD_EUR,USD_GBP,USD_JPY を叩いて body["USD_EUR"].rate を読んでください。
カスタム関数のキャッシュについて Google が実際に述べていること
上のコードでは CacheService を使っていますが、その理由は正確に押さえておきましょう。Google のカスタム関数ガイドは Cache サービスを 「動作はするが、カスタム関数では特に有用ではない」 と評価しています。キャッシュの利点が本当に効くのは、実行をまたいだ場合 — 同じペアが繰り返し再計算されるケース — だけであり、1 回のこぼれ出た配列の内部ではありません。ドキュメント化された最適化は配列のバッチ処理であり、キャッシュは有用な二番手です。
ドキュメント化されたキャッシュの上限は、キーが最大 250 文字、値が最大 100 KB、上限 1,000 件、有効期限は 1 秒から 21,600 秒(6 時間)まで、既定は 600 秒です。キャッシュ呼び出しの 1 日あたりのクォータは公開されていません。
もう 1 つドキュメント化された落とし穴を。回避策として広く出回っているので触れておきますが、更新を強制するために NOW() を引数に加えると関数が壊れます。Google 曰く: 「カスタム関数の引数は決定的でなければなりません……カスタム関数がこれらの揮発性の組み込み関数に基づく値を返そうとすると、Loading... が無限に表示されます」。
方法 3: スケジュール実行のレート表(本番向けパターン)
カスタム関数は Sheets の気分次第で再計算されます。これは、他人が読むシートにとってはまさに間違った性質です。堅牢なパターンは、セルからの取得そのものをやめることです。スケジュールに従ってレートを表に書き込み、あとは素朴な数式で参照します。
更新スクリプト
var PAIRS = ['USD_EUR', 'USD_GBP', 'USD_JPY', 'USD_CAD', 'USD_AUD', 'USD_CHF'];
function refreshRates() {
var key = PropertiesService.getScriptProperties().getProperty('FINEXLY_API_KEY');
var res = UrlFetchApp.fetch(
'https://api.finexly.com/v1/convert?q=' + PAIRS.join(','),
{ headers: { Authorization: 'Bearer ' + key }, muteHttpExceptions: true }
);
if (res.getResponseCode() !== 200) {
console.error('Finexly refresh failed: ' + res.getContentText());
return; // keep yesterday's rates rather than blanking the sheet
}
var data = JSON.parse(res.getContentText());
var stamp = new Date();
var rows = PAIRS.map(function (p) {
return [p, p.split('_')[0], p.split('_')[1], data[p].rate, stamp];
});
var sheet = SpreadsheetApp.getActive().getSheetByName('Rates') ||
SpreadsheetApp.getActive().insertSheet('Rates');
sheet.clear();
sheet.getRange(1, 1, 1, 5)
.setValues([['Pair', 'From', 'To', 'Rate', 'Updated (UTC)']])
.setFontWeight('bold');
sheet.getRange(2, 1, rows.length, 5).setValues(rows);
}これを、よそで見かけるスクリプトと分ける 2 つのディテールがあります。1 つめは、セルごとではなく setValues() の呼び出しが 1 回であること。範囲へのまとめ書き込みは劇的に高速です。2 つめは、取得に失敗したとき表をクリアせずに早期リターンすること。これによりプロバイダ側の一時的な不調があっても、古いがラベル付きのレートが残ります。空白だらけのシートが下流の合計値をすべて静かにゼロにしてしまう事態を避けられます。
トリガーの作成
function installTrigger() {
ScriptApp.getProjectTriggers().forEach(function (t) {
if (t.getHandlerFunction() === 'refreshRates') ScriptApp.deleteTrigger(t);
});
ScriptApp.newTrigger('refreshRates').timeBased().everyHours(1).create();
}Google は、時間主導型トリガーが 「最短で 1 分ごと、最長で月 1 回の頻度で」 実行されること、そして発火時刻が意図的にばらつくことをドキュメント化しています。「午前 9 時の定期トリガーを作成した場合、Apps Script は午前 9 時から 10 時の間の時刻を選びます」。everyMinutes(n) を使う場合、n は 1、5、10、15、30 のいずれかでなければなりません — 他の値は受け付けられません。
レートの読み取り
=XLOOKUP("USD_EUR", Rates!A:A, Rates!D:D)
=A2 * XLOOKUP($B$1 & "_" & $C$1, Rates!A:A, Rates!D:D)これでワークブック内のすべての換算がローカルのセルから即座に解決され、一貫した 1 つのレートを使い、目に見えるタイムスタンプを伴います。最後の点こそ、監査担当者が尋ねてくるところです。
実際にぶつかることになるクォータと上限
以下は Google が公開している Apps Script の数値です。これらを前提に設計する前に把握しておく価値があります。
| 上限 | 個人アカウント(gmail.com) | Google Workspace アカウント |
|---|---|---|
| URL Fetch の呼び出し | 20,000 / 日 | 100,000 / 日 |
| トリガーの合計実行時間 | 90 分 / 日 | 6 時間 / 日 |
| プロパティの読み書き | 50,000 / 日 | 500,000 / 日 |
| カスタム関数の実行時間 | 30 秒 / 実行 | 30 秒 / 実行 |
| スクリプトの実行時間 | 6 分 / 実行 | 6 分 / 実行 |
| ユーザーあたり・スクリプトあたりのトリガー数 | 20 | 20 |
| URL Fetch の URL 長 | 2 KB / 呼び出し | 2 KB / 呼び出し |
?q= バッチに詰め込めるペア数の実質的な天井です。100 を優に超えますが、無制限ではありません。API 側では、Finexly の無料プランが月 1,000 リクエスト、毎分 10 リクエストまで許容します。1 時間ごとのトリガーなら月におよそ 730 リクエストで、無料枠に余裕をもって収まります。単発のカスタム関数呼び出しをいくつか足すなら Starter プランを検討したくなるでしょう。現行のプラン構成は料金ページにあります。なお、ヒストリカルレートには有料プランが必要です。過去日付のレートが必要でかつ予算がゼロなら、個人的・非業務的な用途に限り GOOGLEFINANCE が正直な答えのままです。
すべてのレスポンスには X-RateLimit-Limit、X-RateLimit-Used、X-RateLimit-Units ヘッダーが付くので、res.getAllHeaders() から使用状況をログに残し、上限が近づくのを察知できます。
よくあるエラーと対処法
| 表示されるもの | 原因 | 対処 |
|---|---|---|
GOOGLEFINANCE からの #N/A | 非対応または打ち間違いのペア、あるいは Apps Script / Sheets API 経由でのヒストリカルデータ要求 | 両方の ISO コードを確認。自動化には API を使う |
「Exceeded maximum execution time (line 0).」を伴う #ERROR! | 個別のカスタム関数呼び出しが多すぎる | バッチ処理の FX_CONVERT_RANGE パターンに切り替える |
いつまでも Loading... | NOW()、RAND() などの揮発性関数をカスタム関数の引数に渡している | 取り除く。Google は非対応と明記している |
401 UNAUTHORIZED / invalid token | API キーが未設定または誤り | スクリプト プロパティが設定され、ヘッダーが Bearer <key> になっているか確認 |
429 RATE_LIMIT_EXCEEDED | 毎分または月間の上限に到達 | キャッシュの TTL を延ばす、1 回の呼び出しでより多くのペアをまとめる、またはアップグレードする |
You do not have permission to call X service. | カスタム関数が認可を要するサービスを呼び出した | そのロジックをトリガー実行される関数へ移す |
| ヒストリカル数式が余分な列にこぼれる | ドキュメント化された挙動 — ヒストリカル結果は見出し付きの配列で返る | INDEX(..., 2, 2) で包む |
どの方法を選ぶべきか
- 個人用シート、ちょっとした参照、お金が絡まない場合:
GOOGLEFINANCE。無料で即座に使え、ライセンス制限も問題になりません。 - 業務用スプレッドシートの換算列: バッチ処理版の Apps Script カスタム関数。データソースが予測可能で、ライセンスの曖昧さがなく、範囲あたり呼び出しは 1 回です。
- 同僚・クライアント・監査担当者が読むもの全般: スケジュール実行のレート表。更新サイクルごとに 1 つのレート、目に見えるタイムスタンプ、そして Sheets がいつ再計算する気になるかへの依存がありません。
代わりに Excel で作業していますか。同等の方法 — Power Query、WEBSERVICE、通貨データ型 — は Excel でライブ為替レートを取得する方法で解説しています。まだプロバイダを比較検討中なら、通貨 API 比較が違いを整理していますし、どのレートも Finexly の通貨コンバーターで検算できます。
よくある質問
Google Sheets で無料でライブ為替レートを取得するには?
=GOOGLEFINANCE("CURRENCY:USDEUR") は無料で、セットアップも不要です。ただし Google が明記する利用制限 — このデータは「金融業界の専門家による業務利用、または非金融企業における他の専門職による業務利用を目的としたものではありません」 — と、ヒストリカル値が Apps Script や Sheets API 経由では読み取れないことに注意してください。コストゼロでライセンス済みの代替が欲しいなら、月 1,000 リクエストの無料 API プランで 1 時間ごとの更新(約 730 回の呼び出し)を余裕でカバーできます。
GOOGLEFINANCE はどのくらいの頻度で為替レートを更新しますか?
Google Finance の免責事項に掲載された表では、通貨データの遅延は 3 分、提供元は Morningstar と記載されています。ネット上でよく繰り返される 20 分ではありません。あれは "price" 属性に付随する証券相場の一般的な数値です。それとは別に、Google は Sheets が数式を再計算する頻度を一度も公開していないため、セル内の数値の鮮度は当てにできるものではありません。
Apps Script の中で GOOGLEFINANCE を使えますか?
ヒストリカルデータについては使えません。Google はこう述べています。「ヒストリカルデータは Sheets API または Apps Script 経由でダウンロードまたはアクセスすることはできません。試みた場合、#N/A エラーが表示されます」。また、どの Apps Script サービスにも GOOGLEFINANCE メソッドは存在しません。スクリプトができるのは、セルがすでに計算した値を読むことだけです。コード内でレートが必要なら、UrlFetchApp で通貨 API を呼び出してください。
Google Sheets の通貨数式が遅い、または #ERROR! が出るのはなぜですか?
カスタム関数の呼び出しはそれぞれが Apps Script サーバーへの個別のラウンドトリップであり、1 回の実行は 30 秒が上限です。個別の呼び出しが数百回あればタイムアウトします。範囲を受け取って配列を返し、1 回の呼び出しで列全体をカバーする。レートはキャッシュする。そして定期実行するものはすべて、セルではなく時間主導型トリガーへ取得処理を移してください。
Google Sheets でヒストリカル為替レートを取得できますか?
はい、2 つの方法があります。GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,1), DATE(2026,1,31), "DAILY") は日次の時系列を返します。"price" は有効なヒストリカル属性ではないので "close" を使い、Google が日付を UTC 正午として扱うため値が 1 日ずれ得ることも忘れないでください。もう 1 つは、有料プランの API からヒストリカルレートを取得し、トリガーでシートに書き込む方法です。自動化に耐えるのはこちらだけです。
ライセンス済みで分単位に新鮮な為替レートを、あなたのスプレッドシートに入れる準備はできましたか。無料の 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 →