ブログに戻る

通貨ボラティリティの計算方法:開発者ガイド

V
Vlado Grigirov
September 07, 2026
Currency API Exchange Rates Volatility Historical Data Python Risk Management

通貨ボラティリティの計算方法を知っているかどうかは、一晩で2%動いても静かに吸収できるマルチカレンシー対応アプリケーションと、午前3時にあなたを叩き起こすアプリケーションとの分かれ目になります。ボラティリティは、為替レートがどこまで動きそうかを教えてくれるただ一つの数値であり、FXを扱うシステムにおける実務上の判断はほぼすべてこれに依存しています。見積もりレートの有効期間、価格に上乗せするバッファの厚み、ヘッジするタイミング、アラートを出す基準 — どれもそうです。

やっかいなのは、ボラティリティの計算を扱うチュートリアルの多くが株式向けに書かれていることです。それらは日次終値、年間252営業日、そして曖昧さのない単一の建値を前提にしています。外国為替にはそのどれもありません。分散型の相対取引(OTC)市場で週5日24時間動き続け、公式の終値は存在せず、EUR/USDの「価格」はどちら向きに建値するかで変わります。

本記事では、実際の数式、FX特有の落とし穴、そして過去の為替レートデータから実現ボラティリティを計算するPythonとJavaScriptの実動コードを順に見ていきます。

いま通貨ボラティリティが重要な理由

2026年9月は、ボラティリティについて考えるのに絶好のタイミングです。というのも、市場は今年の大半を不気味なほど静かな地合いで過ごし、そのあと一時的に静かでなくなったからです。

夏の間、新興国通貨のボラティリティはG7通貨よりも低い状態が200営業日近く続きました。ブルームバーグは、この連続記録が途切れなければ2000年以来の長さになると指摘しています。ドル調達のキャリートレードは2008年以来最長の連勝を記録し、ブラジルレアル、コロンビアペソ、トルコリラで構成されるユーロ調達の人気バスケットは年初来で約19%上昇し、2005年以来最も強い年初来パフォーマンスになったと報じられました。キャリー戦略は穏やかな市場でしか機能しないため、その成績自体がボラティリティのシグナルです。

そして9月初旬、日本の財務省によるさらなる介入を見込んだ市場参加者のポジション調整により、円は1営業日で対ドル2%超上昇し、8月初旬以来の高値となる155.28を付けました。その前には7月31日の日米協調介入があり、さらにUSD/JPYが160を突破したあと、4月と5月の2か月で過去最大となる11兆7,300億円(約730億ドル)の財務省による介入が行われていました。

このコントラストこそが教訓のすべてです。平均ボラティリティは低かった。しかし、ある特定の1日の実現ボラティリティは途方もなく大きかった。 過去1年の平均値をもとにFXバッファを設定していたシステムは、まさに肝心なその日に大きく外していたはずです。ボラティリティを正しく、そして継続的に測ることが、それを防ぎます。

通貨ボラティリティが実際に測っているもの

ボラティリティとは、リターンの標準偏差を年率換算したものです。方向性の予測ではありませんし、値動きの大きさそのものでもありません。それは散らばりの尺度です。つまり、ある通貨ペアの日次リターンが平均の周りにどれだけ広く散らばっているか、ということです。

重要なのは2種類です。

  • 実現(ヒストリカル)ボラティリティ — 実際に観測されたレートから遡って計算します。時系列データがあれば自分で算出でき、本記事が扱うのはこちらです。
  • インプライドボラティリティ — FXオプションの価格から逆算されます。市場による将来の予想値です。スポットレートからは導出できず、オプションのデータフィードが必要になります。

プライシング、請求、トレジャリーダッシュボード、リスクアラートといった用途のアプリケーション開発者にとっては、実現ボラティリティで十分ですし、過去レートがすでに手元にあるなら計算コストもかかりません。

数値の感覚をざっくり掴んでおくと、EUR/USDのようなメジャーペアは平穏な時期で年率5〜10%、ストレス時で10〜15%程度に収まることが多いです。新興国通貨ペアは通常その2〜3倍になります。これらのレンジは時期によって動くので、決めつけずに測るべきなのです。

計算式:対数リターン、標準偏差、年率換算

計算は3ステップです。

ステップ1 — レートを対数リターンに変換する。

r_t = ln(P_t / P_t-1)

ステップ2 — 選んだウィンドウでそのリターンの標準偏差を取る(標本標準偏差、つまり n − 1 で割るほうを使います)。

ステップ3 — 年率換算する。1年あたりの観測回数の平方根を掛けます。

annualised_volatility = stdev(r) * sqrt(N)

まとめると、こうなります。

σ_annual = stdev( ln(P_t / P_t-1) ) × √N

単純な変化率ではなく対数リターンを使う理由

単純な変化率は非対称です。1.10から1.20への動きは+9.09%ですが、1.20から1.10へ戻る動きは−8.33%です。本来この2つは大きさが同じで符号が逆であるべきです。対数リターンならそうなります — ln(1.20/1.10)ln(1.10/1.20) は符号が違うだけです。

これは株式よりもFXではるかに重要で、理由は建値の反転にあります。EUR/USDとUSD/EURは同じ市場を表しています。変化率でボラティリティを計算すると、どちら向きに建値したかによってわずかに異なる2つの答えが出てしまい、これは明らかにおかしい。対数リターンは反転に対して対称です。ln(1/x) = −ln(x) であり、標準偏差は符号を無視します。同じペアなら、どちら向きでも同じボラティリティです。

対数リターンは時間方向に加算できるため、複数日の集計も簡単です。

なぜ √N なのか — そしてFXでの N の値

分散が時間に対して線形に増える(標準的なランダムウォークの仮定のもとで)ため、ボラティリティは時間の平方根に比例します。日次ボラティリティを年率に換算するには、√(1年あたりの日数) を掛けます。

株式のチュートリアルでは 252、つまり米国取引所の営業日数の近似値を使います。FXは違います。市場は日曜の夜から金曜の夜まで途切れなく動いており、年間およそ 260 の平日セッションから、薄商いの祝日を数日引いた程度です。ほとんどのFXデータプロバイダーは、その国の市場が休みの日も含め、すべての平日にレートを配信します。

実務上のルール:N は、他の資産クラスから借りてきた慣行ではなく、自分のデータのサンプリング頻度に合わせること。

データ頻度N(年率換算係数)
日次(平日、FXの慣行)260
日次(252営業日の株式慣行)252
週次52
月次12
時間足(24×5)約6,240
252と260の差は、結果を相対で約1.6%変えます。ダッシュボードなら些細ですが、自社の数値をベンダーのものと突き合わせるなら無視できません。どちらを選ぶにせよ、それを文書化し、一貫して使い続けてください。

ステップ1:きれいな過去の為替レートデータを用意する

ボラティリティの精度は、その土台となる時系列データの質で決まります。/v1/timeseries エンドポイントへの1回の呼び出しで日次系列を取得できます。

curl -G "https://api.finexly.com/v1/timeseries" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d base=EUR \
  -d symbols=USD,JPY,GBP \
  -d start_date=2026-06-08 \
  -d end_date=2026-09-05

レスポンスは日付をキーとしたマップです。

{
  "success": true,
  "base": "EUR",
  "start_date": "2026-06-08",
  "end_date": "2026-09-05",
  "rates": {
    "2026-06-08": { "USD": 1.1421, "JPY": 178.62, "GBP": 0.8447 },
    "2026-06-09": { "USD": 1.1408, "JPY": 178.94, "GBP": 0.8451 }
  }
}

リクエストは1回、系列も1本、ページネーションのループもありません。パラメータの完全なリファレンスは Finexly APIドキュメント にあります。日付範囲を扱う際のより広いパターンは、ヒストリカル為替レートAPIガイドで解説しています。

FX特有の4つのデータ問題

出力を信用する前に、以下に対処してください。どれも株式のボラティリティ入門記事には出てきませんが、4つとも数値を歪めます。

1. 公式の終値が存在しない。 FXは分散型で、取引終了のベルを鳴らす人はいません。プロバイダーごとにスナップショットを取る時刻が異なります — UTC22時、UTC深夜0時、ECBの中央欧州時間14時15分の参照レート、あるいはロンドン16時のWM/Reutersフィキシングなど。1本の系列の中でスナップショット時刻を混在させると、人為的な分散が入り込みます。1つの基準を選び、決して混ぜないこと。自分のプロバイダーがどうしているか分からなければ、為替レートAPIはどこからデータを取得しているのかの解説から始めるとよいでしょう。

2. 週末とギャップ。 市場は金曜の夜に閉まり、日曜の夜に再開します。金曜→月曜のリターンはカレンダー上およそ65時間をカバーしますが、素朴な計算では1「日」として扱われます。多くの実務家はこれを受け入れて平日ベースで年率換算します — これが標準的なやり方です — が、一貫性は必須です。週末のレートを系列に前方補完してはいけません。同じ値が並ぶと、標準偏差が人為的に押し下げられます。

3. 基準通貨の非対称性。 前述のとおり、対数リターンは反転の問題を数学的に解決します。しかし、どの通貨を基準にリスクを測るのかは、依然として決める必要があります。ユーロ建てで測ったドルエクスポージャーのボラティリティと、ドル建てで測った同じペアのそれは、数値が同一でもビジネス上の問いとしては別物です。基準通貨(ニュメレール)を明示しましょう。

4. 三角合成のクロスレート。 たとえばプロバイダーがSEK/USDをNOK/USDで割ってSEK/NOKを導出している場合、その結果は両レッグのノイズと、両者のタイミングのずれをそのまま引き継ぎます。合成クロスは、直接建値される市場よりも目に見えて高いボラティリティを示すことがあります。クロスレートのガイドでは、三角合成が安全な場合とそうでない場合を説明しています。

精度にも注意してください。リターンを計算する前にJPYペアを小数点以下2桁に切り捨てると、小さな値動きがゼロに量子化され、ボラティリティが下方に偏ります — 一般的な原則は通貨の丸めと小数点以下の桁数を参照してください。保存はフル精度で行い、丸めるのは表示のときだけにします。

ステップ2:Pythonで実現ボラティリティを計算する

依存関係の少ない完全な実装がこちらです。requests と標準ライブラリだけを使い、pandasは不要です。

import math
import statistics
import requests

FX_DAYS_PER_YEAR = 260  # weekday sessions; use 252 for the equity convention


def fetch_series(base, symbol, start, end, api_key):
    url = "https://api.finexly.com/v1/timeseries"
    params = {
        "base": base,
        "symbols": symbol,
        "start_date": start,
        "end_date": end,
    }
    headers = {"Authorization": "Bearer " + api_key}
    response = requests.get(url, params=params, headers=headers, timeout=10)
    response.raise_for_status()
    return response.json()["rates"]


def log_returns(rates, symbol):
    """Ordered log returns from a date-keyed rates map."""
    dates = sorted(rates.keys())
    series = [rates[d][symbol] for d in dates]
    return [
        math.log(series[i] / series[i - 1])
        for i in range(1, len(series))
        if series[i] > 0 and series[i - 1] > 0
    ]


def annualised_volatility(returns, periods_per_year=FX_DAYS_PER_YEAR):
    if len(returns) < 2:
        raise ValueError("need at least two returns")
    return statistics.stdev(returns) * math.sqrt(periods_per_year)


rates = fetch_series("EUR", "USD", "2026-06-08", "2026-09-05", "YOUR_API_KEY")
returns = log_returns(rates, "USD")

vol = annualised_volatility(returns)
print("Observations:      {}".format(len(returns)))
print("Daily volatility:  {:.4%}".format(vol / math.sqrt(FX_DAYS_PER_YEAR)))
print("Annual volatility: {:.2%}".format(vol))

statistics.stdev標本標準偏差(分母が n − 1)で、これがまさに必要なものです。NumPyに切り替える場合、numpy.std は既定で母標準偏差になる点に注意してください — ddof=1 を渡せば一致します。

本番コードで残しておく価値のあるガードが2つあります。対数を取る前に正でないレートをスキップすること、そして観測数が少なすぎるウィンドウでは数値を返さないことです。9個のデータ点から計算した30日ボラティリティは、30日ボラティリティではありません。

ステップ3:同じ計算をJavaScriptで

こちらも数値計算ライブラリは不要です。

const FX_DAYS_PER_YEAR = 260;

async function fetchSeries(base, symbol, start, end, apiKey) {
  const url = new URL('https://api.finexly.com/v1/timeseries');
  url.searchParams.set('base', base);
  url.searchParams.set('symbols', symbol);
  url.searchParams.set('start_date', start);
  url.searchParams.set('end_date', end);

  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  if (!res.ok) throw new Error(`Finexly returned ${res.status}`);
  const body = await res.json();
  return body.rates;
}

function logReturns(rates, symbol) {
  const dates = Object.keys(rates).sort();
  const series = dates.map((d) => rates[d][symbol]);
  const out = [];
  for (let i = 1; i < series.length; i += 1) {
    if (series[i] > 0 && series[i - 1] > 0) {
      out.push(Math.log(series[i] / series[i - 1]));
    }
  }
  return out;
}

function annualisedVolatility(returns, periodsPerYear = FX_DAYS_PER_YEAR) {
  if (returns.length < 2) throw new Error('need at least two returns');
  const mean = returns.reduce((a, b) => a + b, 0) / returns.length;
  const variance =
    returns.reduce((acc, r) => acc + (r - mean) ** 2, 0) / (returns.length - 1);
  return Math.sqrt(variance) * Math.sqrt(periodsPerYear);
}

const rates = await fetchSeries('EUR', 'USD', '2026-06-08', '2026-09-05', 'YOUR_API_KEY');
const vol = annualisedVolatility(logReturns(rates, 'USD'));
console.log(`Annualised volatility: ${(vol * 100).toFixed(2)}%`);

(returns.length - 1) という分母に注目してください — Python版と同じ標本分散の補正です。

ローリングボラティリティと地合いの変化の検知

固定ウィンドウの単一の数値では、いつ荒れ始めたのかはほとんど分かりません。ローリングボラティリティなら分かりますし、ダッシュボードで実際に欲しくなるのはこちらです。

def rolling_volatility(rates, symbol, window=30,
                       periods_per_year=FX_DAYS_PER_YEAR):
    dates = sorted(rates.keys())
    series = [rates[d][symbol] for d in dates]
    returns = [math.log(series[i] / series[i - 1]) for i in range(1, len(series))]
    return_dates = dates[1:]

    out = []
    for i in range(window - 1, len(returns)):
        chunk = returns[i - window + 1:i + 1]
        out.append((
            return_dates[i],
            statistics.stdev(chunk) * math.sqrt(periods_per_year),
        ))
    return out


for date, vol in rolling_volatility(rates, "USD", window=30)[-5:]:
    print("{}  {:.2%}".format(date, vol))

ウィンドウの選択は、事実ではなくトレードオフです。

  • 10日 — 反応が非常に速く、その分ノイズも大きい。アラート向きで、プライシングには不向き。
  • 30日 — よく使われる既定値。数セッションで反応しつつ、暴れすぎない。
  • 90日 — 滑らかで安定。ヘッジ比率やプライシングバッファの設定に向く。

地合いの変化を捉える実用的なシグナルがボラティリティ比率です。10日ボラティリティを90日ボラティリティで割ります。おおむね1.5を超える水準が続いていれば、短期の散らばりが長期のベースラインを明確に上回っているということです。先に述べた介入局面の円ペアに当てはめると、この比率は急騰する一方で90日の数値はほとんど動きません — それこそが要点です。長いウィンドウはイベントを覆い隠し、短いウィンドウはそれを見つけます。

これを多数のペアで継続的に回すつもりなら、まず通貨APIのキャッシュとエラーハンドリングについてのメモを読んでください。過去の日次レートは公開後は不変なので、無期限にキャッシュできます — ページを読み込むたびに1年分の履歴を取り直すのではなく、最新のウィンドウだけを再計算しましょう。料金プランのページで、各ティアのリクエスト数を確認できます。

ボラティリティの数値を意思決定に変える

ボラティリティを計算するのは簡単です。価値が生まれるのは、それを使うところです。具体的な応用を4つ挙げます。

  1. 見積もりレートの有効期間。 顧客に提示する価格は、あなたが顧客に売った短期オプションのようなものです。t 日の保有期間における期待ドリフトは、およそ σ_annual × √(t / 260) です。年率8%のボラティリティなら、24時間の見積もりは約0.5%の期待ドリフトを抱えます。20%なら1.2%近くになります。ずっと15分固定にするのではなく、ボラティリティが上がったらTTLを短くしましょう。
  1. プライシングバッファ。 FXマージンを2%と決め打ちするのではなく、buffer = k × σ_annual × √(settlement_days / 260) のようにスケールさせます。ストレス局面では自動的にバッファが広がり、市場が落ち着けば縮まるので、隠れたリスクを抱えずに競争力を保てます。
  1. ヘッジの発動条件。 エクスポージャーそのものはリスクではありません。エクスポージャー×ボラティリティがリスクです。ボラティリティ4%のペアに対する200万ドルのエクスポージャーは、ボラティリティ30%のペアに対する40万ドルよりも小さな問題です。ヘッジの判断は想定元本ではなく exposure × σ で順位付けしましょう。通貨ヘッジのガイドで手段を解説しています。何にヘッジをかけるべきかは、ボラティリティの数値が教えてくれます。
  1. アノマリー検知。 新しい日次の値動きを、直近30日の標準偏差に対するzスコアに変換し、±3を超えたらアラートを出します。これは本物の市場イベントも、不正なデータも捕まえます — 古いままのフィードや三角合成を誤ったクロスは、たいてい誰かがレポートで気づくより先に、ありえない外れ値として姿を現します。

これらの値動きをパーセントではなくトレーダー向けの単位で表したい場合は、pipとは何かをご覧ください。

よくある間違い

  • 対数リターンの代わりに変化率を使う。 非対称性が入り込み、答えが建値の向きに依存してしまいます。
  • 母標準偏差を使う。 ddof=1 を付けない numpy.std() はボラティリティを過小評価し、短いウィンドウでは特にひどくなります。
  • 週末や祝日を前方補完する。 値の繰り返しはリターンゼロの日となり、機械的にボラティリティを引き下げます。
  • 間違った N で年率換算する。 週次データを52ではなく260で年率換算すると、約2.2倍大きな数値になります。
  • スナップショット時刻の異なるボラティリティ同士を比べる。 プロバイダーが2つ、フィキシング時刻が2つなら、比較できない数値が2つできるだけです。
  • 年率の数値を1つ出しただけでリスクを語る。 ボラティリティはクラスター化します。穏やかな月と荒れた週が平均されて、そのどちらも表していない中途半端な数値になります。代表値と併せて、必ずローリング系列も出しましょう。
  • 低ボラティリティ=低リスクだと思い込む。 2026年のキャリーに優しい静かな地合いは、介入のヘッドラインが円を1営業日で2%動かすその瞬間まで静かでした。低い実現ボラティリティは直近の過去についての記述であって、来週についての約束ではありません。

よくある質問

通貨ペアのボラティリティは、どれくらいが普通ですか?

EUR/USDやGBP/USDのようなメジャーペアは、歴史的に平穏時で年率およそ5〜10%、ストレス下で10〜15%程度で推移してきました。新興国通貨ペアは通常その2〜3倍です。経験則に頼るよりも、対象のペアについて90日ローリングボラティリティを計算し、自前のベースラインを持つほうがよいでしょう。水準は地合いとともに変わります。

FXボラティリティの年率換算には252日と260日のどちらを使うべきですか?

260のほうが適しています。FX市場は単一の取引所のカレンダーに従うのではなく、すべての平日に取引されるからです。252は株式の慣行ですが、それでも広く使われています。差は相対で約1.6%なので、大事なのはどちらかを選び、文書化し、数値を比較するあらゆる場所で一貫して適用することです。

為替レートAPIからインプライドボラティリティを計算できますか?

できません。インプライドボラティリティはFXオプションの価格から逆算するもので、オプションのデータフィードが必要です。スポットや過去のレート系列から計算できるのは実現ボラティリティです。アプリケーションコードでのプライシング、ヘッジのしきい値、アラートには、通常は実現ボラティリティが適切な指標です。

どれくらいの期間の過去データが必要ですか?

最低でもウィンドウ長より1つ多い観測値が必要ですが、それでは推定が不安定になります。実務上の下限としては、30日ウィンドウなら30観測を使い、さらに現在の水準を長期のベースラインと比較できるよう、少なくとも1年分の履歴を取得してください。/v1/timeseries エンドポイントは、任意の日付範囲を1回のリクエストで返します。

自分のボラティリティの数値がデータプロバイダーのものと違うのはなぜですか?

ほぼ必ず次の4つのいずれかが原因です。年率換算係数の違い(252か260か)、母標準偏差か標本標準偏差か、日次レートのスナップショット時刻の違い、単純リターンか対数リターンか。データが間違っていると判断する前に、この4点を確認してください。

ボラティリティは通貨がどちらに動くかを予測できますか?

できません。ボラティリティが測るのは散らばりであって、方向ではありません。年率20%のボラティリティを持つペアは大きく動くと予想されますが、上に動くのか下に動くのかについて、この計算は何も語りません。相場観を持つためではなく、リスクの大きさを測るために使ってください。


ライブデータでボラティリティを計算する準備はできましたか?Finexly APIキーを無料で取得 — クレジットカードは不要です。170以上の通貨のリアルタイムおよび過去のレート、月1,000リクエストの無料枠、そして日付範囲をまとめて1回で返す /v1/timeseries エンドポイントが使えます。まずは無料の為替レートAPIから始めて、データのニーズが増えたらアップグレードしてください。

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 →

この記事を共有する