2025.09.29

先物価格データの分析をしてみる

はじめに

グループ研究開発本部・AI研究開発室のS.Sです。
今回もGPTに聞きながら金融データを分析するシリーズの続きとして、原油の先物価格のデータを分析してみたいと思います。
よく先物とスポットの乖離をベースに短期の方向感を占う話がありますが、そのあたりを実データの分析を交えながら見てみることにします。

先物曲線からの短期予測

先物とスポットの乖離をベースに予測を行う方法を聞いてみると、以下のような回答が得られます。

先物の複数限月の価格を並べることで、先物曲線(term structure)が得られます。この形状は市場参加者の将来予想を反映します。

  • コンタンゴ(Contango)
    限月が先に行くほど価格が高い。通常は保管コストや金利が反映されている。現物価格が将来上がるという強いシグナルではない。

  • バックワーデーション(Backwardation)
    限月が先に行くほど価格が安い。現物の需給逼迫を示唆することが多く、短期的に現物価格が上昇しやすい。

限月間の傾きを計算したり、スポットと1ヶ月先のスプレッドなどを特徴量にするのが一般的です。

分析対象データ

無料のデータソースから先物の価格データを長期で取得するのは一般的にはハードルが高いですが、米国エネルギー省のページには軽質スイート原油のスポット・先物価格データが提供されています。
今回はこのデータを分析してみることにします。

分析環境セットアップ

以下のコードで上記のページから取得してきたデータを読み込んでおきます。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df_spot = pd.read_csv("Cushing_OK_WTI_Spot_Price_FOB.csv")
df_c1 = pd.read_csv("Cushing_OK_Crude_Oil_Future_Contract_1.csv")
df_c2 = pd.read_csv("Cushing_OK_Crude_Oil_Future_Contract_2.csv")
df_c3 = pd.read_csv("Cushing_OK_Crude_Oil_Future_Contract_3.csv")
df_c4 = pd.read_csv("Cushing_OK_Crude_Oil_Future_Contract_4.csv")

df_spot["Day"] = df_spot["Day"].pipe(pd.to_datetime)
df_c1["Day"] = df_c1["Day"].pipe(pd.to_datetime)
df_c2["Day"] = df_c2["Day"].pipe(pd.to_datetime)
df_c3["Day"] = df_c3["Day"].pipe(pd.to_datetime)
df_c4["Day"] = df_c4["Day"].pipe(pd.to_datetime)

df_price = pd.concat((df_spot.set_index(["Day"]).squeeze().sort_index(),
           df_c1.set_index(["Day"]).squeeze().sort_index(),
           df_c2.set_index(["Day"]).squeeze().sort_index(),
           df_c3.set_index(["Day"]).squeeze().sort_index(),
           df_c4.set_index(["Day"]).squeeze().sort_index()), axis=1, keys=["spot", "1M", "2M", "3M", "4M"]).dropna()

試しに読み込んだデータを表示してみると以下のようになります。

個別分析

スポット・1ヶ月先物の乖離

それではまずスポット・1ヶ月先物の乖離で翌日のスポットの動きを予測してみます。
分析は以下のようなコードで行います。

pd.concat((df_price[["spot", "1M"]].pct_change(axis=1).iloc[:, -1],
           df_price["spot"].pct_change().shift(-1)), axis=1, keys=["x", "y"])\
.loc["2000-01-01":"2025-01-01"]\
.loc[lambda x: x["x"].expanding().rank(pct=True) >2/3]["y"].cumsum().plot(label="long")
pd.concat((df_price[["spot", "1M"]].pct_change(axis=1).iloc[:, -1],
           df_price["spot"].pct_change().shift(-1)), axis=1, keys=["x", "y"])\
.loc["2000-01-01":"2025-01-01"]\
.loc[lambda x: x["x"].expanding().rank(pct=True) <1/3]["y"].cumsum().plot(label="short")
plt.legend()

スプレッドのパーセンタイルランクを見てプラスに大きく振れた時はロングし、マイナスに大きく振れた時はショートすると、以下のような累積リターンが得られます。
長期でみると一定のペースでリターンが積み上がっており、精度はまずまずという感じです。

1ヶ月物・2ヶ月物の乖離

さらに先をみて1ヶ月物を取引するケースでも同様の傾向が当てはまりますが、2020年のコロナショックで需要が一時的に急減した時は予測を大きく外してしまっています。
この辺りは他の需要・供給を示す指標と組み合わせて分析する必要がありそうです。

スプレッドベースの戦略まとめ

上記の分析だとスポット・1ヶ月物の乖離をベースにスポットを取引するのが比較的よい結果(SR: 0.4)になりました。
取引の制約上、スポット価格を直接取引できないケースもあるかとは思いますが、この種の戦略を考える上でのヒントにはなるかと思います。

まとめ

今回の分析では、先物カーブに織り込まれている情報をうまく取り出すことで、短期のトレンドが予測できるという事実を原油価格データで確かめました。
コストやターンオーバーなど他にも考慮すべき部分はありますが、短期のコモディティ取引の一つのファクターにはなることでしょう。

最後に

グループ研究開発本部 AI研究開発室では、データサイエンティスト/機械学習エンジニアを募集しています。ビッグデータの解析業務などAI研究開発室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。皆さんのご応募をお待ちしています。

  • Twitter
  • Facebook
  • はてなブックマークに追加

グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。

 
  • AI研究開発室
  • 大阪研究開発グループ

関連記事