BTCオプション取引のプレミアム価格トレンド予測：LSTMによるアプローチ


## 概要
BTCオプション取引のプレミアム価格のトレンド（上昇・下落）を予測するLSTMモデルの構築方法について解説します。オプション取引は複雑な要素を含みますが、時系列データ分析に強いLSTMを活用することで、ある程度の予測が可能になります。

## 目次
1. はじめに
2. データの準備
3. データの前処理とLSTM用のデータセット作成
4. LSTMモデルの構築
5. 学習と評価
6. まとめ

## 1. はじめに
オプション取引は株式・仮想通貨・商品など様々な市場で行われるデリバティブ取引の一種です。特にBTCオプション取引は、先物と比較してボラティリティが高く、価格変動が激しい特徴があります。

本記事では以下の流れで予測モデルを構築します：
- 過去のオプション取引データ（プレミアム、ギリシャ指標、原資産価格など）の読み込み
- データのシンボル（銘柄）ごとの整理と前処理
- LSTM用のサンプルとラベルの作成
- モデルの構築と学習
- テストデータによる精度評価

## 2. データの準備
本実装ではMongoDBからデータを取得していますが、CSVやAPIなど他のデータソースでも代用可能です。

```python
db = MongoDataLoader()
df = db.load_data(OPTION_TICKER)
```

想定するデータフレームのカラム：
- date: 価格記録日時
- symbol: オプション銘柄シンボル
- ask1Price, bid1Price: 最良売気配・買気配
- ask1Iv, bid1Iv, markIv: オプションIV
- underlyingPrice: 原資産価格
- delta, gamma, vega, theta: ギリシャ指標
- openInterest: オープン・インタレスト
- markPrice: マーク価格

## 3. データの前処理とLSTM用のデータセット作成

### 3.1 シンボルごとの時系列整理

```python
def process_option_data(df: pd.DataFrame) -> Dict[str, pd.DataFrame]:
    """
    Process option data and organize it by symbol into time series
    """
    df['date'] = pd.to_datetime(df['date'])
    symbol_groups = {}

    for symbol in df['symbol'].unique():
        symbol_df = df[df['symbol'] == symbol].copy()
        symbol_df = symbol_df.sort_values('date')
        symbol_df.set_index('date', inplace=True)
        symbol_groups[symbol] = symbol_df

    return symbol_groups
```

### 3.2 データセット作成
window_size（本実装では24）ステップ分のデータから、次のステップの価格動向を予測します。

```python
def create_lstm_dataset(
    data: np.ndarray, window_size: int = 24
) -> Tuple[np.ndarray, np.ndarray]:
    """
    LSTM用の入力(X), 出力(y)を作成する関数
    次の1ステップで ask1Price が上昇 or 下降を予測する
    """
    X, y = [], []
    for i in range(len(data) - window_size):
        X.append(data[i : i + window_size])
        current_price = data[i + window_size - 1, 0]
        next_price = data[i + window_size, 0]
        label = 1 if next_price > current_price else 0
        y.append(label)

    return np.array(X), np.array(y)
```

### 3.3 特徴量選択とスケーリング

使用する特徴量：
```python
feature_cols = [
    'ask1Price', 'bid1Price', 'ask1Iv', 'bid1Iv', 'markIv',
    'underlyingPrice', 'delta', 'gamma', 'vega', 'theta',
    'openInterest', 'markPrice'
]
```

## 4. LSTMモデルの構築

```python
model = Sequential()
model.add(
    LSTM(
        32,
        input_shape=(X_train.shape[1], X_train.shape[2]),
        return_sequences=False
    )
)
model.add(Dense(1, activation='sigmoid'))

model.compile(
    loss='binary_crossentropy',
    optimizer='adam',
    metrics=['accuracy']
)
```

モデルの構成：
- LSTM層（32ユニット）
- Dense層（シグモイド活性化関数）
- バイナリクロスエントロピー損失関数
- Adam最適化アルゴリズム

## 5. 学習と評価

### 5.1 データ分割
```python
X_train, X_test, y_train, y_test = train_test_split(
    X_all, y_all, test_size=0.2, shuffle=True, random_state=42
)
```

### 5.2 学習実行
```python
history = model.fit(
    X_train, y_train,
    epochs=10,
    batch_size=32,
    validation_split=0.1,
    verbose=1
)
```

### 5.3 評価
```python
y_pred_prob = model.predict(X_test)
y_pred_class = (y_pred_prob >= 0.5).astype(int).flatten()

accuracy = accuracy_score(y_test, y_pred_class)
print(f"Test Accuracy: {accuracy:.4f}")

print("Confusion Matrix:")
print(confusion_matrix(y_test, y_pred_class))

print("Classification Report:")
print(classification_report(y_test, y_pred_class, target_names=['Down','Up']))
```

### 5.4 実行結果

```
Test Accuracy: 0.7064

Confusion Matrix:
[[12511  3208]
 [ 4584  6232]]

Classification Report:
              precision    recall  f1-score   support
        Down       0.73      0.80      0.76     15719
          Up       0.66      0.58      0.62     10816
    accuracy                           0.71     26535
   macro avg       0.70      0.69      0.69     26535
weighted avg       0.70      0.71      0.70     26535
```

結果の解釈：
- 全体の予測精度（Accuracy）は約71%で、ランダムな予測（50%）を大きく上回っています
- 下落予測（Down）の精度が上昇予測（Up）よりもやや高い傾向が見られます：
  - 下落の適合率（Precision）: 73%
  - 下落の再現率（Recall）: 80%
  - 上昇の適合率: 66%
  - 上昇の再現率: 58%
- 混同行列から、モデルは下落傾向をより正確に捉えられていることがわかります
  - 真の下落を下落と予測: 12,511件
  - 真の上昇を上昇と予測: 6,232件
  - 誤って下落と予測: 4,584件
  - 誤って上昇と予測: 3,208件

この結果は、モデルが市場の動きをある程度捉えられていることを示していますが、特に上昇トレンドの予測については改善の余地があることを示唆しています。

## 6. まとめ
本実装はBTCオプション取引のプレミアム価格トレンドをLSTMで予測する基本的なアプローチです。実運用に向けては以下の検討が必要です：

- 特徴量の拡張：ボラティリティ指標やオンチェーンデータの活用
- モデル構造の改良：多層化やAttention機構の導入
- 予測対象の工夫：24時間後の価格動向予測など
- 評価指標の改良：実際のP/Lを考慮した指標の導入

金融市場は外部要因の影響を受けやすく、モデルの予測精度は変動することがあります。継続的なデータ収集と検証、適切なリスク管理との組み合わせが重要です。

## 実装コード全体
以下が実装の完全なコードです。`tensorflow`、`pandas`、`numpy`、`scikit-learn`などの必要なライブラリをインストールしてお使いください。

```python
import os
import sys
from typing import Tuple, Dict
import numpy as np
import pandas as pd
from datetime import datetime, timedelta

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# Get the absolute path of the current directory
current_dir = os.path.dirname(os.path.abspath(__file__))
# Get the path of the parent directory
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)

from mongodb.data_loader_mongo import MongoDataLoader
from common.constants import *
from option_pricing import simulate_option_prices

def process_option_data(df: pd.DataFrame) -> Dict[str, pd.DataFrame]:
    """
    Process option data and organize it by symbol into time series
    """
    df['date'] = pd.to_datetime(df['date'])
    symbol_groups = {}

    for symbol in df['symbol'].unique():
        symbol_df = df[df['symbol'] == symbol].copy()
        symbol_df = symbol_df.sort_values('date')
        symbol_df.set_index('date', inplace=True)
        symbol_groups[symbol] = symbol_df

    return symbol_groups

def create_lstm_dataset(
    data: np.ndarray, window_size: int = 24
) -> Tuple[np.ndarray, np.ndarray]:
    """
    LSTM用の入力(X), 出力(y)を作成する関数
    次の1ステップで ask1Price が上昇 or 下降を予測する
    """
    X, y = [], []
    for i in range(len(data) - window_size):
        # 直近 window_size ステップ分
        X.append(data[i : i + window_size])
        # （ラベル生成）: 次ステップの ask1Price が直前より大きいかどうか
        current_price = data[i + window_size - 1, 0]  # 0番目の列 = ask1Price
        next_price = data[i + window_size, 0]
        label = 1 if next_price > current_price else 0
        y.append(label)

    X = np.array(X)  # shape: (サンプル数, window_size, 特徴量数)
    y = np.array(y)
    return X, y

def main():
    db = MongoDataLoader()
    df = db.load_data(OPTION_TICKER)

    symbol_timeseries = process_option_data(df)

    # ------------------------------------------------------
    # 1. 時系列長が 50 ステップ未満のシンボルを排除
    # ------------------------------------------------------
    all_X, all_y = [], []
    window_size = 24

    # 有力と思われる特徴量
    feature_cols = [
        'ask1Price',     # 予測対象も含め、過去の推移から学習
        'bid1Price',
        'ask1Iv',
        'bid1Iv',
        'markIv',
        'underlyingPrice',
        'delta',
        'gamma',
        'vega',
        'theta',
        'openInterest',  # 必要に応じて
        'markPrice'
    ]

    for symbol, ts_df in symbol_timeseries.items():
        if len(ts_df) < 50:
            continue

        # 必要なカラムがすべて存在するかチェック
        missing_cols = [col for col in feature_cols if col not in ts_df.columns]
        if missing_cols:
            # 無い場合はスキップするなどの判断
            continue

        # 各列を float に変換（文字列の場合があるため）
        for col in feature_cols:
            ts_df[col] = ts_df[col].astype(float)

        # 特徴量をまとめて numpy 配列へ
        features_data = ts_df[feature_cols].values  # shape: (サンプル数, 特徴量数)

        # スケーリング (MinMaxScaler)
        scaler = MinMaxScaler()
        features_data_scaled = scaler.fit_transform(features_data)

        # LSTM用データセット作成
        X, y = create_lstm_dataset(features_data_scaled, window_size=window_size)

        if len(X) > 0:
            all_X.append(X)
            all_y.append(y)

    # もし有効データがなければ終了
    if len(all_X) == 0:
        print("有効な学習データがありません（必要なカラムがない、または時系列が短い）")
        return

    X_all = np.concatenate(all_X, axis=0)
    y_all = np.concatenate(all_y, axis=0)

    # ------------------------------------------------------
    # 2. 学習データ (train) と テストデータ (test) に分割
    # ------------------------------------------------------
    X_train, X_test, y_train, y_test = train_test_split(
        X_all, y_all, test_size=0.2, shuffle=True, random_state=42
    )

    # ------------------------------------------------------
    # 3. LSTM モデル構築
    # ------------------------------------------------------
    model = Sequential()
    model.add(
        LSTM(
            32,
            input_shape=(X_train.shape[1], X_train.shape[2]),
            return_sequences=False
        )
    )
    model.add(Dense(1, activation='sigmoid'))

    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

    # ------------------------------------------------------
    # 4. 学習
    # ------------------------------------------------------
    history = model.fit(
        X_train, y_train,
        epochs=10,        # 例
        batch_size=32,    # 例
        validation_split=0.1,
        verbose=1
    )

    # ------------------------------------------------------
    # 5. 推論 & 評価
    # ------------------------------------------------------
    y_pred_prob = model.predict(X_test)
    y_pred_class = (y_pred_prob >= 0.5).astype(int).flatten()

    # Accuracy
    accuracy = accuracy_score(y_test, y_pred_class)
    print(f"Test Accuracy: {accuracy:.4f}")

    # Confusion Matrix
    cm = confusion_matrix(y_test, y_pred_class)
    print("Confusion Matrix:")
    print(cm)

    # Classification Report (Precision, Recall, F1-score)
    print("Classification Report:")
    print(classification_report(y_test, y_pred_class, target_names=['Down','Up']))

    # 必要に応じてモデルを保存
    # model.save('lstm_trend_model.h5')

if __name__ == "__main__":
    main()
```

### 必要なライブラリ
このコードを実行するために必要なライブラリは以下の通りです：

```bash
pip install tensorflow pandas numpy scikit-learn
```

### 注意点
- MongoDBに関連する部分（`MongoDataLoader`）は、お使いの環境に合わせて適宜修正してください
- `OPTION_TICKER`や他の定数は`common.constants`から読み込んでいますが、これも環境に応じて適切に設定してください
- データの形式や列名は、お使いのデータセットに合わせて調整が必要です

## 参考文献・リンク
- TensorFlow LSTM Documentation
- Keras Documentation
- scikit-learn Documentation

#Bitcoin #機械学習 #DeepLearning #LSTM #Python #オプション取引