0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人開発の米国株アプリで「予想変動」の定義が3つ混ざっていた話(ATMストラドルに一本化)

0
Last updated at Posted at 2026-10-09

米国株のオプション分析アプリ「SIGNUM HQ」を個人で作っています。銘柄画面に出している「予想変動(Implied Move)」の数字が、実は画面ごとに別の計算になっていたことに気づき、定義を1つに集約しました。その経緯と実装の要点を書きます。

何が起きたか

ある日、半導体株の予想変動が画面で「±9.0%」と出ていました。同じ時刻に、満期の近いATMストラドルの中値から手計算すると次の値でした。

ストラドル中値 83.42 ÷ 株価 1,053.98 = 7.9%

9.0%と7.9%で食い違います。原因を追うと、impliedMovePct という同じ名前のフィールドに、定義が3種類混ざっていました。

どこで使っていたか 実際の計算
バッチ(ウォッチリスト・ポートフォリオ)とレポート生成 (コールウォール − プットフロア) ÷ 株価。OI(建玉)の壁の間の「幅」
収集用Lambda・ダッシュボード コールとプットで別々に選んだ最寄りの行使価格の「前日終値」の和
スコア計算 株価±2%の窓の中で最初に見つかった契約。約定がなければ前日終値

画面もAIに渡すプロンプトも、これを全部「±x% 予想変動」として読んでいました。

一本化した定義

impliedMovePct = (ATMコール中値 + ATMプット中値) ÷ 現物 × 100

決めたルールは4つです。

  1. 満期は、基準日以上で最も近いもの。決算を見たいときは「決算後の最初の満期」を指定する(引け後発表なら翌日以降、寄り前発表なら当日以降)。
  2. ATMは、現物に最も近い行使価格を「1つ」選び、コールもプットも同じ行使価格にする。
  3. 価格は中値(bidとaskの真ん中)。リアルタイムの中値があればそれ(basis: 'live')、なければ終値時点の中値(basis: 'eod')。
  4. 直近の約定価格(day.close)は使わない。流動性の薄い行使価格では、中値と数十%ずれることがある。実測では、あるコールの前日の約定価格が62.5、中値が41.5でした。

実装の骨子

実際のコードはもう少し防御的ですが、考え方はこの程度です(簡略版)。

type Leg = { strike: number; mid: number | null };

export function atmStraddlePct(spot: number, calls: Leg[], puts: Leg[]) {
  // 現物に近い順に行使価格を並べ、コールとプットの両方に中値がある最初の1つを使う
  const strikes = [...new Set(calls.map((c) => c.strike))]
    .sort((a, b) => Math.abs(a - spot) - Math.abs(b - spot))
    .slice(0, 3);
  for (const k of strikes) {
    const c = calls.find((x) => x.strike === k)?.mid;
    const p = puts.find((x) => x.strike === k)?.mid;
    if (c != null && p != null) {
      return { strike: k, straddle: +(c + p).toFixed(2), pct: +(((c + p) / spot) * 100).toFixed(1) };
    }
  }
  return null; // 無ければ無し。前日の値などで埋めない
}

ポイントは最後の return null です。値が取れないときに別の基準の数字で穴埋めすると、また定義が混ざります。

名前で区別する

OIの壁の間の幅も有用な数字ですが、予想変動ではありません。そこで別名にしました。

wallRangePct = (コールウォール − プットフロア) ÷ 現物 × 100

こちらには「±」を付けず、「予想変動」「implied move」とも呼ばない、というルールにしています。定義が2つあること自体は問題ではなく、同じ名前で2つ呼ぶことが問題でした。

「いつの値か」を持ち回る

市場が閉まっている間はリアルタイムの中値がありません。以前の設計では終値時点の値を画面に載せず、予想変動の欄が全部「—」になっていました。今は終値時点の値も載せ、値の基準(liveかeod)とその値のセッション日付を一緒に返し、画面では「10/2終値」のような添え書きを付けます。数字には、いつの値かを持たせるのが基本だと考えています。

検証

  • 定義の関数は副作用のない純関数にして、サーバーとクライアントの両方から同じものを呼ぶ
  • 単体テストを付ける
  • 手計算の値(冒頭の7.9%)と突き合わせて確認する
  • 読み取り専用のAPIも用意して、外部のベンダー呼び出しやキャッシュ書き込みは行わない(保存済みの値がなければnullを返す)

アプリについて

SIGNUM HQ は、米国株のオプション(マックスペイン、ガンマエクスポージャー、コールウォールなど)とダークプール比率を、銘柄ごとにまとめて見られる無料アプリです。iPhoneとAndroidがあり、日本語・英語・韓国語に対応しています。投資の助言ではなく、公開データの整理です。

この記事を読んだ方向けのPRO 1か月無料クーポンもあります(広告なし+マイ銘柄100件。無料プランは5件)。PRO 1か月無料、以降は月額¥1,280で自動更新(いつでも解約可)・先着500名・10/30まで・iPhone。このリンクを開くとクーポンが適用されます(Qiita読者専用)。

Androidは同じリンクを開くと個人用コードが発行されます(30日間無料、以降は月額¥1,280で自動更新・30日以内に解約すれば0円・先着200名・10/30まで。Googleのお支払い方法の登録が必要)。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?