Strasmore Research
学習 Matt Connor著者: Matt Connor

ポートフォリオのデルタとベータ加重を解説

ティッカー間でデルタを単純合計できない理由と、SPY同等株数への換算方法を小さなポートフォリオで手計算し、売買判断に役立つ形で解説します。

ポートフォリオ・デルタは、一つの問いに答える単一の数値である。市場全体が1%動いた場合、ポートフォリオ全体がどの程度動くかを概算で示す。各ポジションのデルタを単純に合計しても、この問いへの答えにはならない。ベータ・ウェイティングは、合計値に意味を持たせるための調整である。すべての保有銘柄を、SPYの同等株数として換算する。

ティッカー間でポートフォリオのデルタが合計できない理由

デルタは、原資産が一ドル動いたときにポジションの価値がどれだけ変化するかを示す。株式一株のデルタは一である。オプション一契約は株式一百株を対象とするため、デルタ〇・三のコールは三十デルタのエクスポージャーを持つ。この単一ポジションの見方については、オプションのデルタが示すもので説明している。

問題は、二つ目のティッカーを加えたときに生じる。高価格でベータの高い銘柄の一百デルタと、低価格でディフェンシブな銘柄の一百デルタは、同じ数であってもエクスポージャーは大きく異なる。前者は、これまで指数を上回る値動きをしてきた数万ドル分の株式に相当する。後者は、これまで値動きが指数を下回ってきた数千ドル分の株式に相当する。これらを足すと二百になるが、その数字は実際の売買判断に使える単位ではない。

ベータ加重デルタとは何か

ベータ加重では、ポートフォリオ内のすべてのデルタを、選択した一つのベンチマークのデルタとして表示し直します。米国株式ポートフォリオでは、通常SPYを使います。二つの倍率で計算します。

一つ目はベータです。これは、選択した期間における株式の日次リターンと指数の日次リターンの関係を回帰した傾きで、株式のベンチマークに対する過去の感応度を示します。ベータが1.4であれば、その期間中、指数が1%動くごとに、その株式は平均で約1.4%動いたことを意味します。

二つ目は価格比率です。株式の価格をベンチマークの価格で割って求めます。デルタは株数で数えますが、価格の異なる株式は金額も異なります。価格比率によって、これらを同じ尺度に換算できます。

ポジションの生デルタにこの二つの倍率を掛けると、ベータ加重デルタになります。これは、測定期間中に同じ値動きをしたと仮定した場合のSPYの株数を示します。以下のパネルでは、2026年6月30日までの一年間について、日次終値のリターンから各銘柄のベータを算出し、SPYに対する価格比率と、その積を示しています。SPYは基準となる銘柄としてリストに含まれ、ベータは1、価格比率も1です。したがって、SPY一株はベータ加重デルタ一単位に相当します。

クエリ保有1株あたりのベータ、価格比率、SPY相当株数
各数値の背後にある正確なSQL
WITH
    sessions AS
    (
        SELECT
            ticker                                               AS ticker,
            toDate(toTimeZone(window_start, 'America/New_York')) AS d,
            toFloat64(argMax(close, window_start))               AS px
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker IN ('SPY', 'NVDA', 'AAPL', 'MSFT', 'XOM', 'JNJ', 'KO')
          AND window_start >= toDateTime('2025-07-01 04:00:00')
          AND window_start <  toDateTime('2026-07-01 04:00:00')
          AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
             + toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
          AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
             + toMinute(toTimeZone(window_start, 'America/New_York'))) <  960
        GROUP BY ticker, d
    ),
    steps AS
    (
        SELECT
            ticker,
            d,
            px,
            any(px) OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_px
        FROM sessions
    ),
    daily_ret AS
    (
        SELECT ticker, d, (px / prev_px) - 1 AS r
        FROM steps
        WHERE prev_px > 0
    ),
    bench AS
    (
        SELECT d, r AS spy_r
        FROM daily_ret
        WHERE ticker = 'SPY'
    ),
    betas AS
    (
        SELECT
            s.ticker                                 AS ticker,
            covarPop(s.r, b.spy_r) / varPop(b.spy_r) AS beta_vs_spy,
            1                                        AS k
        FROM daily_ret AS s
        INNER JOIN bench AS b ON b.d = s.d
        GROUP BY s.ticker
    ),
    prices AS
    (
        SELECT ticker, argMax(px, d) AS close_px
        FROM sessions
        GROUP BY ticker
    ),
    spy_price AS
    (
        SELECT argMax(px, d) AS spy_close, 1 AS k
        FROM sessions
        WHERE ticker = 'SPY'
    )
SELECT
    betas.ticker                                                        AS ticker,
    round(betas.beta_vs_spy, 2)                                         AS beta_vs_spy,
    round(prices.close_px / spy_price.spy_close, 3)                     AS price_vs_spy,
    round(betas.beta_vs_spy * prices.close_px / spy_price.spy_close, 3) AS spy_shares_per_share
FROM betas
INNER JOIN prices ON prices.ticker = betas.ticker
INNER JOIN spy_price ON spy_price.k = betas.k
ORDER BY beta_vs_spy DESC
Run this yourself

NVDAは、ベータ1.86で首位となり、SPYの0.268倍の価格で取引されています。この二つを掛けると、一株でSPY0.498株分の指数エクスポージャーを持つことになります。7銘柄の末尾はゼロを下回ります。XOMのこの期間のベータは-0.36でした。これは指数に対する緩やかな逆方向の傾きであり、単に値動きが小さいことを示すものではありません。一株はSPY-0.067株に換算されます。いずれも帳簿上は一デルタです。しかし、そのデルタがさらされるエクスポージャーには大きな差があります。また、小数点以下二桁で表示されたベータも、特定の期間に基づく推定値にすぎないことが分かります。この点については、本稿の最後で取り上げます。

オプションのデルタの算出元

株式のデルタは1株当たり1で固定されています。オプションのデルタは固定値ではありません。行使価格、満期までの残存期間、原資産価格、インプライド・ボラティリティに応じて変動します。下のパネルは、2026年6月30日に取引された、満期まで20〜45日残るAAPLの全契約について、終値からの行使価格の乖離幅を2%刻みで区分し、デルタを示したものです。

クエリ権利行使価格別のAAPLコールおよびプットのデルタ(満期まで20~45日)
各数値の背後にある正確なSQL
SELECT
    concat(if(bucket_pct > 0, '+', ''), toString(bucket_pct), '%') AS strike_vs_spot,
    round(avgIf(contract_delta, contract_delta > 0), 3)            AS call_delta,
    round(avgIf(contract_delta, contract_delta < 0), 3)            AS put_delta,
    count()                                                        AS contract_count
FROM
(
    SELECT
        toInt32(round((toFloat64(strike_price) / toFloat64(underlying_close) - 1) * 50)) * 2 AS bucket_pct,
        toFloat64(delta)                                                                     AS contract_delta
    FROM global_markets.options_greeks
    WHERE underlying_symbol = 'AAPL'
      AND date >= toDate('2026-06-30')
      AND date <  toDate('2026-07-01')
      AND iv_converged = 1
      AND volume > 0
      AND days_to_expiry BETWEEN 20 AND 45
      AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) <= 0.12
)
GROUP BY bucket_pct
HAVING countIf(contract_delta > 0) > 0 AND countIf(contract_delta < 0) > 0
ORDER BY bucket_pct
Run this yourself

-12%の区分では、コールのデルタは取引された4契約の平均で0.924、プットは-0.084でした。+10%では、コールの平均デルタは0.106、プットは-0.834でした。同じ行使価格のコールとプットは、符号が逆のデルタを持ちます。そのため、コールの売りとプットの買いはいずれも、現物株の買いポジションを相殺します。満期が近づくにつれて曲線全体がどのように変化するかは、オプションのグリークスが時間とともにどう変化するかで解説しています。

一つの小さなポジションブックを単一の数値に集約する

手作業で組んだ三つのポジションからなるブックを考える。AAPLを300株ロングする。満期までおよそ一カ月で、アット・ザ・マネーから約5%上のAAPLコールを3枚ショートする。標準的なカバードコールのオーバーレイである。二つ目の銘柄のヘッジとして、満期が同程度でアット・ザ・マネー付近のKOプットを5枚ロングする。株式と契約の数量は仮定値である。パネルに表示されるデルタとベータはすべて計測値である。

クエリ3レッグのブック:未調整デルタとベータ加重デルタ
各数値の背後にある正確なSQL
WITH
    sessions AS
    (
        SELECT
            ticker                                               AS ticker,
            toDate(toTimeZone(window_start, 'America/New_York')) AS d,
            toFloat64(argMax(close, window_start))               AS px
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker IN ('SPY', 'AAPL', 'KO')
          AND window_start >= toDateTime('2025-07-01 04:00:00')
          AND window_start <  toDateTime('2026-07-01 04:00:00')
          AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
             + toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
          AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
             + toMinute(toTimeZone(window_start, 'America/New_York'))) <  960
        GROUP BY ticker, d
    ),
    steps AS
    (
        SELECT
            ticker,
            d,
            px,
            any(px) OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_px
        FROM sessions
    ),
    daily_ret AS
    (
        SELECT ticker, d, (px / prev_px) - 1 AS r
        FROM steps
        WHERE prev_px > 0
    ),
    bench AS
    (
        SELECT d, r AS spy_r
        FROM daily_ret
        WHERE ticker = 'SPY'
    ),
    betas AS
    (
        SELECT
            s.ticker                                 AS ticker,
            covarPop(s.r, b.spy_r) / varPop(b.spy_r) AS beta_vs_spy
        FROM daily_ret AS s
        INNER JOIN bench AS b ON b.d = s.d
        GROUP BY s.ticker
    ),
    prices AS
    (
        SELECT ticker, argMax(px, d) AS close_px, 1 AS k
        FROM sessions
        GROUP BY ticker
    ),
    spy_price AS
    (
        SELECT argMax(px, d) AS spy_close, 1 AS k
        FROM sessions
        WHERE ticker = 'SPY'
    ),
    opt_delta AS
    (
        SELECT
            underlying_symbol                       AS ticker,
            if(toFloat64(delta) > 0, 'call', 'put') AS kind,
            avg(toFloat64(delta))                   AS per_share_delta
        FROM global_markets.options_greeks
        WHERE date >= toDate('2026-06-30')
          AND date <  toDate('2026-07-01')
          AND iv_converged = 1
          AND volume > 0
          AND days_to_expiry BETWEEN 25 AND 40
          AND (
                (underlying_symbol = 'AAPL' AND toFloat64(delta) > 0
                 AND toFloat64(strike_price) / toFloat64(underlying_close) BETWEEN 1.03 AND 1.07)
             OR (underlying_symbol = 'KO' AND toFloat64(delta) < 0
                 AND toFloat64(strike_price) / toFloat64(underlying_close) BETWEEN 0.97 AND 1.03)
          )
        GROUP BY ticker, kind
    ),
    legs AS
    (
        SELECT
            tupleElement(leg, 1) AS leg_no,
            tupleElement(leg, 2) AS position,
            tupleElement(leg, 3) AS ticker,
            tupleElement(leg, 4) AS kind,
            tupleElement(leg, 5) AS qty,
            tupleElement(leg, 6) AS multiplier
        FROM
        (
            SELECT arrayJoin([
                (1, 'Long 300 AAPL',      'AAPL', 'stock', 300., 1.),
                (2, 'Short 3 AAPL calls', 'AAPL', 'call',   -3., 100.),
                (3, 'Long 5 KO puts',     'KO',   'put',     5., 100.)
            ]) AS leg
        )
    )
SELECT
    position                                                                                          AS position,
    round(raw_share_delta)                                                                            AS raw_share_delta,
    round(beta_vs_spy, 2)                                                                             AS beta_vs_spy,
    round(bw_delta)                                                                                   AS beta_weighted_delta,
    round(sum(bw_delta) OVER (ORDER BY leg_no ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW))       AS running_book_delta,
    round(sum(bw_delta) OVER (ORDER BY leg_no ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) * spy_close / 100.) AS dollars_per_1pct_spy
FROM
(
    SELECT
        l.leg_no                                                            AS leg_no,
        l.position                                                          AS position,
        l.qty * l.multiplier * if(l.kind = 'stock', 1., o.per_share_delta)  AS raw_share_delta,
        bt.beta_vs_spy                                                      AS beta_vs_spy,
        sp.spy_close                                                        AS spy_close,
        raw_share_delta * bt.beta_vs_spy * pr.close_px / sp.spy_close       AS bw_delta
    FROM legs AS l
    LEFT  JOIN opt_delta AS o  ON o.ticker = l.ticker AND o.kind = l.kind
    INNER JOIN betas     AS bt ON bt.ticker = l.ticker
    INNER JOIN prices    AS pr ON pr.ticker = l.ticker
    INNER JOIN spy_price AS sp ON sp.k = pr.k
)
ORDER BY leg_no
Run this yourself

株式ポジションは、1株当たり一つの生デルタとして、300のデルタをもたらす。コールのショートは-98、プットのロングは-217である。この三つを合計すると一つの数値になる。ベータ・ウェイトを適用すると、別の数値になる。

対象期間におけるAAPLのベータは0.88、KOは-0.27だった。KOはこの12カ月間、指数に対して負の傾きを示した。各ポジションをベータと、SPYに対する価格で調整すると、株式ポジションは103SPY株、コールのショートは-34、プットは6となる。プットのポジションは詳しく見る価値がある。生デルタ-217はKOのショートを示す。ショート・エクスポージャーに負のベータを掛けると、帳簿上はプラスとなり、6SPY株に相当する小幅な指数ロングになる。符号を別にして重要なのは規模である。生デルタでは大きく見えるヘッジが、指数ベースではその一部にすぎない数量へ換算される。また、その効果は市場ではなくKOに対して発揮される。累計欄には各ポジションが順番に反映され、最終的にブックは76のベータ・ウェイト・デルタとなる。

この規模のベータ加重デルタが実際に意味すること

76のベータ加重デルタを持つポジションは、計測期間中、同数のSPY株を保有していた場合と同じように動いています。正の数値は、ポートフォリオが指数に対してロングであることを示します。負の数値はショートであることを示し、トレーダーはこれをデルタをショート方向に傾けると表現します。最後の列は、累積値を金額に換算したものです。他の条件が変わらなければ、SPYが1%動くと、ポートフォリオは565ドル変動します。

この数値をフラットにするには、同じ大きさで符号が反対のベータ加重デルタを追加します。SPY株のショートでは、一対一で調整できます。SPY株一株は、定義上、ベータ加重デルタ一単位です。SPYオプションでは、選択したコントラクトのデルタに応じて、その一部を調整します。原株ポジションを縮小する場合は、最初のパネルに示した、その銘柄固有の換算率で調整します。いずれの方法にも、それぞれ異なるコストとグリークスが伴います。

ベータ・ウェイトが機能しない場面

ベータは回帰分析による推定値であり、測定期間によって結果が変わります。下のパネルでは、同じ二つのベータを、すべて同じ日付を終点とする六つのルックバック期間で再計算しています。

クエリ同じ2つのベータを6種類のルックバック期間で測定
各数値の背後にある正確なSQL
WITH
    sessions AS
    (
        SELECT
            ticker                                               AS ticker,
            toDate(toTimeZone(window_start, 'America/New_York')) AS d,
            toFloat64(argMax(close, window_start))               AS px
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker IN ('SPY', 'AAPL', 'KO')
          AND window_start >= toDateTime('2024-04-01 04:00:00')
          AND window_start <  toDateTime('2026-07-01 04:00:00')
          AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
             + toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
          AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
             + toMinute(toTimeZone(window_start, 'America/New_York'))) <  960
        GROUP BY ticker, d
    ),
    steps AS
    (
        SELECT
            ticker,
            d,
            px,
            any(px) OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_px
        FROM sessions
    ),
    daily_ret AS
    (
        SELECT ticker, d, (px / prev_px) - 1 AS r
        FROM steps
        WHERE prev_px > 0
    ),
    bench AS
    (
        SELECT d, r AS spy_r
        FROM daily_ret
        WHERE ticker = 'SPY'
    ),
    paired AS
    (
        SELECT
            s.ticker                                                 AS ticker,
            s.r                                                      AS r,
            b.spy_r                                                  AS spy_r,
            row_number() OVER (PARTITION BY s.ticker ORDER BY s.d DESC) AS rn
        FROM daily_ret AS s
        INNER JOIN bench AS b ON b.d = s.d
        WHERE s.ticker IN ('AAPL', 'KO')
    ),
    windows AS
    (
        SELECT arrayJoin([30, 60, 90, 180, 252, 504]) AS lookback
    )
SELECT
    w.lookback                                                                                       AS lookback_sessions,
    round(covarPopIf(p.r, p.spy_r, p.ticker = 'AAPL') / varPopIf(p.spy_r, p.ticker = 'AAPL'), 2)     AS aapl_beta,
    round(covarPopIf(p.r, p.spy_r, p.ticker = 'KO')   / varPopIf(p.spy_r, p.ticker = 'KO'), 2)       AS ko_beta
FROM paired AS p
CROSS JOIN windows AS w
WHERE p.rn <= w.lookback
GROUP BY w.lookback
HAVING countIf(p.ticker = 'AAPL') > 0 AND countIf(p.ticker = 'KO') > 0
ORDER BY lookback_sessions
Run this yourself

直近の30セッションでは、AAPLのベータは0.54でした。一方、1.14504セッションに対する値です。KOは短い期間で-1.04、長い期間で-0.03でした。すべての6推定値は算術的に正確です。ただし、それぞれ異なる問いに答えています。したがって、ベータ・ウェイトで調整したブック・デルタは、プラットフォームが採用した期間の影響を受けます。ある期間ではわずかにマイナス、次の期間ではわずかにプラスとなるディフェンシブ銘柄は、異常ではなく通常のケースです。上で示したブックの計算結果におけるすべての符号は、その選択に依存しています。

相関の動きも二つ目の限界です。ベータは通常のセッションの平均値です。市場全体が広く下落する局面では、通常は独自のペースで動く銘柄も連動して動く傾向があり、測定されたベータは1に近づきます。静かな市場で算出したベータでは均衡して見えるブックでも、ヘッジが必要なセッションでは大きく偏っている可能性があります。集中リスクは、反対側から同じ盲点を説明しています。要約統計量が示すのは分布の中心であり、テールではありません。

三つ目に、この計算は一次近似であり、ガンマを考慮していません。ベータ・ウェイト調整後のデルタは、現在の価格におけるブック価値の傾きを示し、その傾きが維持されると仮定しています。デルタ自体が変化する割合を示すガンマは、計算に含まれていません。ショート・オプションを保有するブックは、ベータ・ウェイト調整後のデルタが小さく見えても、指数が3%動けば性質が急速に変わる可能性があります。計算に使ったデルタは、そうした価格水準でそれらのポジションをもはや表していません。この数値は、小幅な値動きに対する指標として扱ってください。プロテクティブ・プットのようにテールリスクに備えて構築したポジションは、ベータ・ウェイト調整後の数値では小さく見えますが、その範囲で機能するものではありません。

ベンチマークも選択項目です。小型株のブックをSPYに対してウェイト調整すると、値動きのうち市場全体ではなく企業規模に起因する部分が埋もれます。デルタは複数あるギリシャ指標の一つにすぎず、その他の指標についてはオプションのギリシャ指標の解説で説明しています。

FAQ

ベータ加重デルタとは何ですか?

ベータ加重デルタは、ポートフォリオ内のすべてのポジションを、通常はSPYなど一つのベンチマークの株式数に換算して示したものです。各ポジションの生デルタに、対象資産のベンチマークに対するベータと、両者の価格比を掛け、その結果をポートフォリオ全体で合算します。

ベータ加重デルタは手計算でどのように求めますか?

まず、ポジションの株式換算デルタを求めます。株式は一株当たり1、オプションは契約当たりオプションデルタに100を掛けた値です。これに対象資産のベンチマークに対するベータを掛け、さらに対象資産価格をベンチマーク価格で割った値を掛けます。すべてのポジションについて結果を合算します。

ベータ加重デルタがマイナスであることは何を意味しますか?

ベンチマークが下落すると価値が増え、上昇すると価値が減るポートフォリオであることを示します。おおむね、ベンチマークの株式をその数だけ空売りした場合と同じ方向のエクスポージャーです。トレーダーはこれをデルタ・ショートへの傾斜と呼びます。この数値が有効なのは、小幅な値動きに限られます。

株式のベータがマイナスになることはありますか?

あります。一定の観測期間では起こり得ます。ベータは、株式の日次リターンと指数の日次リターンの関係を示す傾きです。ディフェンシブ銘柄では、ある12カ月間ではわずかにマイナスとなり、次の期間ではわずかにプラスとなることがあります。ベータがマイナスだと、そのポジションのベータ加重デルタの符号も反転します。そのため、この指標は測定対象となった観測期間と併せて読む必要があります。

どのルックバック期間のベータを使えばよいですか?

唯一の正解となる期間はありません。30セッションのベータは直近の動きを反映しますが、大きく変動しやすい指標です。一方、1年または2年のベータはより安定しているものの、事業の変化を反映するまで時間がかかります。上記の安定性パネルでは、同じ銘柄について同じ日に、二つの観測期間の数値がどれほど離れるかを確認できます。

ベータ加重はガンマやボラティリティを考慮しますか?

いいえ。ベータ加重デルタは、現在のデルタと過去のベータに基づく一次近似の指標です。ガンマ、ベガ、セータ、ローは考慮されません。そのため、ショートオプションで構成されたポートフォリオは、ベータ加重デルタではフラットに見えても、大きな値動きに対して相当なリスクを抱えている可能性があります。


上記の各パネルには、その結果を生成したSQLが付属しています。パネルを一つ開き、ティッカーまたは測定期間を変更すれば、Strasmoreターミナルで定義できる任意のポートフォリオに対して、同じベータ加重の計算を実行できます。

#beta weighting#portfolio greeks#delta#hedging#options