Bot トレードロジック 機械学習・データサイエンス

仮想通貨botの開発記録#105(2024/9/16)「LSTM(Long Short-Term Memory)モデルを使って予測を行う自動取引システム」

2024年9月16日

前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。

今回は「LSTM(Long Short-Term Memory)モデルを使って予測を行う自動取引システム」についてまとめました。

きっかけになったのは@blog_ukiさんのポストでした。

紹介されていた論文を読んでみたところ、「技術力があればエッジになりそう」と感じました。

解決したいこと

・少数ショット学習について理解を深める

・少数ショット学習を取り入れた取引システムを作成できるようになる

・少数ショット学習を用いて検証をする

・論文を読んで学んだことを開発に取り入れる経験を積む

Yodaka

とは言ったものの、基礎部分の理解も技術力もまるで足りていないので、
「まずはLSTMモデルを使って価格予測をするbotの開発に手をつけてみよう」
という次第です。

LSTMモデルとは?

LSTM(Long Short-Term Memory)モデルは、リカレントニューラルネットワーク(RNN)の一種で、時系列データや順序が重要なデータの処理に特化しています。以下の特徴があります:

  1. 長期依存性の学習: LSTMは、長期間にわたる依存関係を学習できるため、従来のRNNよりも長いシーケンスデータに対して効果的です。
  2. ゲート機構: LSTMは、以下の3つの主要なゲートを使用して情報の流れを調整します。
    • 入力ゲート: 新しい情報がセル状態にどの程度加えられるかを決定します。
    • 忘却ゲート: 既存のセル状態からどの情報を忘れるかを決定します。
    • 出力ゲート: セル状態からどの情報を出力として使用するかを決定します。
  3. セル状態: セル状態(メモリ)は、長期間にわたる情報を保持し、必要に応じて更新されます。これにより、LSTMは長期依存性を学習できます。

LSTMは、自然言語処理や音声認識、時系列予測など、順序や時間的な情報を扱うタスクに広く使われています。

LSTM(Long Short-Term Memory)モデルと少数ショット学習(Few-Shot Learning)は、異なる目的やアプローチを持っていますが、いくつかの関連点があります。

少数ショット学習との関連

LSTM(Long Short-Term Memory)

  • 用途: 時系列データや順序データの学習に特化したモデルで、長期間の依存関係を学習できる。
  • 特長: 長期的な情報の保持や、シーケンスデータにおけるコンテキストの理解が得意です。

少数ショット学習(Few-Shot Learning)

  • 用途: 少量のサンプルでモデルを学習し、新しいクラスやタスクに適応する能力を持つ学習方法。
  • 特長: 少ないデータからでも効果的に学習し、一般化する能力を持つ。

どのように関連しているのか

  1. 時系列データでの応用:
    • LSTMは時系列データやシーケンスデータに特化しているため、少数ショット学習の場面で時系列データを扱う場合、LSTMを活用することができます。例えば、少ないデータポイントで時系列予測を行う場合、LSTMが有効です。
  2. メタ学習との関連:
    • 少数ショット学習のアプローチの一つにメタ学習(Meta-Learning)があり、メタ学習モデルは過去のタスクから学習し、新しいタスクに迅速に適応することが求められます。LSTMはシーケンスの学習に強いため、メタ学習の一部として使用されることがあります。特に、過去の経験から新しいタスクに迅速に適応する能力を持つLSTMベースのモデルが研究されています。
  3. モデルの転移学習:
    • 少数ショット学習では、転移学習(Transfer Learning)やファインチューニング(Fine-Tuning)が重要です。LSTMを使って事前に大規模な時系列データで訓練されたモデルを持つ場合、それを少数ショットタスクに応じてファインチューニングすることで、新しいタスクへの適応が可能です。

まとめ

LSTMと少数ショット学習は異なる目的を持ちますが、LSTMの能力を活かして少数ショット学習のシナリオに応用することができます。具体的には、少ないデータポイントで時系列データを扱う場合や、メタ学習の一部としてLSTMを利用するケースがあります。

補足

LSTMは少数ショット学習に関連する分野の一つですが、少数ショット学習を効果的に使いこなすためには他にも重要な概念や技術があります。以下のポイントも学ぶと良いでしょう:

  1. メタ学習(Meta-Learning):
    • 少数ショット学習の基本技術で、少量のデータから迅速に学習するためのアプローチです。代表的なメタ学習アルゴリズムにはMAML(Model-Agnostic Meta-Learning)などがあります。
  2. 転移学習(Transfer Learning):
    • 既存のモデルや学習済みの知識を新しいタスクに応用する技術です。少数ショット学習では、事前に訓練されたモデルを微調整することがよく行われます。
  3. プロトタイプネットワーク(Prototypical Networks):
    • クラスの「プロトタイプ」(代表的なサンプル)を学習し、新しいサンプルがどのプロトタイプに近いかで分類を行う手法です。
  4. シーネット(Siamese Networks):
    • 入力データのペア間の類似性を学習するネットワークで、少数ショット学習のタスクでよく使われます。
  5. データ拡張(Data Augmentation):
    • 少ないデータで学習を効果的に行うためのテクニックで、データセットを増やすためのさまざまな手法があります。

コードの雛形

Yodaka

まずはCursorにざっくりした指示を出してプログラムの雛形を作成しました。

import requests
import pandas as pd
import numpy as np
import time
import logging
from tensorflow import keras

# ログの設定を追加
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def fetch_realtime_data(url):
    try:
        # タイムアウトを設定し、エラーハンドリングを改善
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        data = response.json()
        bids_df = pd.DataFrame(data['bids'], columns=['price', 'size'])
        asks_df = pd.DataFrame(data['asks'], columns=['price', 'size'])
        # データ型を明示的に指定
        return pd.DataFrame({
            'bid_price': bids_df['price'].astype(float),
            'bid_size': bids_df['size'].astype(float),
            'ask_price': asks_df['price'].astype(float),
            'ask_size': asks_df['size'].astype(float)
        })
    except requests.exceptions.RequestException as e:
        logger.error(f"データの取得に失敗しました: {e}")
        return None

def create_sequences(data, sequence_length):
    # データ長のチェックを追加
    if len(data) < sequence_length:
        logger.warning(f"データ長が不足しています。必要: {sequence_length}, 実際: {len(data)}")
        return None
    sequences = []
    for i in range(len(data) - sequence_length + 1):
        sequences.append(data.iloc[i:i + sequence_length].values)
    return np.array(sequences)

url = 'https://api.bitflyer.com/v1/getboard?product_code=BTC_JPY'

# LSTMモデルの設計
sequence_length = 10
feature_count = 4
input_layer = keras.Input(shape=(sequence_length, feature_count))
lstm_layer = keras.layers.LSTM(64)(input_layer)
output_layer = keras.layers.Dense(1)(lstm_layer)
model = keras.Model(inputs=input_layer, outputs=output_layer)
model.compile(optimizer='adam', loss='mean_squared_error')

# リアルタイムでデータを取得して評価
while True:
    try:
        new_data_df = fetch_realtime_data(url)
        if new_data_df is not None:
            new_data = create_sequences(new_data_df, sequence_length)
            if new_data is not None:
                # 予測を実行し、結果をログに出力
                prediction = model.predict(new_data)
                logger.info(f"予測結果: {prediction}")
            else:
                logger.warning("シーケンスの作成に失敗しました")
        else:
            logger.warning("データの取得に失敗しました")
    except Exception as e:
        # 予期せぬエラーのハンドリングを追加
        logger.error(f"予期せぬエラーが発生しました: {e}")
    finally:
        # 一定時間待機
        time.sleep(60)

このコードは、仮想通貨のリアルタイム取引データを取得し、LSTM(Long Short-Term Memory)モデルを使って予測を行う自動取引システムの一部です。

このコードの実行フローと詳細は以下の通りです:

1. ライブラリのインポート

  • 必要なライブラリ(requests, pandas, numpy, time, logging, tensorflow.keras)をインポートします。

2. ログの設定

  • ログの設定を行い、ログメッセージのレベルとフォーマットを指定します。

3. 関数 fetch_realtime_data

  • 目的: 指定されたURLからリアルタイムデータを取得します。
  • 処理:
    • HTTPリクエストを送信し、タイムアウトを設定します。
    • レスポンスが正常であればJSONデータを取得し、bidsasksをデータフレームに変換します。
    • 価格とサイズをfloat型に変換し、1つのデータフレームにまとめます。
    • エラーが発生した場合はログにエラーメッセージを記録し、Noneを返します。

4. 関数 create_sequences

  • 目的: データフレームから指定された長さのシーケンスを作成します。
  • 処理:
    • データの長さがシーケンス長より短い場合は警告をログに記録し、Noneを返します。
    • 長さが十分であれば、シーケンスを作成し、numpy配列として返します。

5. LSTMモデルの設計

  • 目的: 時系列データの予測を行うLSTMモデルを設計します。
  • 処理:
    • 入力層としてシーケンスの長さと特徴量の数を設定します。
    • LSTM層と出力層を追加し、adamオプティマイザーとmean_squared_error損失関数でコンパイルします。

6. メインループ

  • 目的: リアルタイムでデータを取得し、モデルで予測を行います。
  • 処理:
    • while Trueループ内で、指定されたURLからデータを取得します。
    • データ取得が成功した場合、シーケンスを作成し、モデルで予測を実行します。
    • 予測結果をログに記録します。
    • データ取得やシーケンス作成に失敗した場合は、それに応じた警告をログに記録します。
    • 予期せぬエラーが発生した場合もエラーログを記録します。
    • 1分ごとにデータの取得と予測を繰り返します(time.sleep(60))。

このフローにより、リアルタイムデータを収集し、LSTMモデルを使って予測し続けるプロセスが実現されています。

全体として、定期的にデータを取得し、そのデータをLSTMモデルに入力して予測を行い、その結果をログに記録する仕組みです。

コードを正しく稼働させるために

Yodaka

このコードは実用に向けていくつかの点で修正や確認が必要です。

  1. モデルの訓練:
    • 現在のコードにはモデルの訓練が含まれていません。予測を行う前に、モデルに適切なデータで訓練する必要があります。
  2. データの前処理:
    • fetch_realtime_dataで取得したデータがモデルの期待する形式(特にシーケンスの長さや特徴量の数)と一致しているか確認が必要です。データのスケーリングや正規化が必要な場合もあります。
  3. エラーハンドリング:
    • データ取得や予測処理中に発生する可能性のあるエラーに対するハンドリングがされていますが、エラーの原因を特定して対処するために追加のデバッグやロギングが有効です。
  4. シーケンスの形状:
    • create_sequences関数で作成したシーケンスがモデルの期待する入力形状 (sequence_length, feature_count) と一致しているか確認する必要があります。
  5. 依存関係の確認:
    • 必要なライブラリ(tensorflow, pandasなど)が正しくインストールされていることを確認してください。

それぞれの問題点を解決するための実行可能なコードは以下の通りです:

1. モデルの訓練

まず、モデルを訓練するためのデータ準備と訓練コードを追加します。

import numpy as np
import pandas as pd
from tensorflow import keras
from sklearn.model_selection import train_test_split

# データのサンプル(この部分は実際のデータに置き換えてください)
def generate_sample_data():
    np.random.seed(0)
    num_samples = 1000
    sequence_length = 10
    feature_count = 4
    X = np.random.rand(num_samples, sequence_length, feature_count)
    y = np.random.rand(num_samples, 1)
    return X, y

# サンプルデータの生成
X, y = generate_sample_data()

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

# LSTMモデルの設計
sequence_length = 10
feature_count = 4
input_layer = keras.Input(shape=(sequence_length, feature_count))
lstm_layer = keras.layers.LSTM(64)(input_layer)
output_layer = keras.layers.Dense(1)(lstm_layer)
model = keras.Model(inputs=input_layer, outputs=output_layer)
model.compile(optimizer='adam', loss='mean_squared_error')

# モデルの訓練
model.fit(X_train, y_train, epochs=10, batch_size=32, validation_data=(X_test, y_test))

2. データの前処理

データをモデルの期待する形式に合わせて前処理を行います。例えば、データを正規化する場合のコードは以下の通りです:

from sklearn.preprocessing import MinMaxScaler

def preprocess_data(df):
    scaler = MinMaxScaler()
    scaled_df = df.copy()
    for column in df.columns:
        scaled_df[column] = scaler.fit_transform(df[[column]])
    return scaled_df

3. エラーハンドリングの強化

エラーハンドリングのコードを改善して、エラーの詳細をログに記録します。

import traceback

def fetch_realtime_data(url):
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        data = response.json()
        bids_df = pd.DataFrame(data['bids'], columns=['price', 'size'])
        asks_df = pd.DataFrame(data['asks'], columns=['price', 'size'])
        return pd.DataFrame({
            'bid_price': bids_df['price'].astype(float),
            'bid_size': bids_df['size'].astype(float),
            'ask_price': asks_df['price'].astype(float),
            'ask_size': asks_df['size'].astype(float)
        })
    except requests.exceptions.RequestException as e:
        logger.error(f"データの取得に失敗しました: {e}\n{traceback.format_exc()}")
        return None

4. シーケンスの形状の確認

シーケンスがモデルの期待する形状に合っているか確認します。コードの一部を改良して、形状を確認するコードを追加します。

def create_sequences(data, sequence_length):
    if len(data) < sequence_length:
        logger.warning(f"データ長が不足しています。必要: {sequence_length}, 実際: {len(data)}")
        return None
    sequences = []
    for i in range(len(data) - sequence_length + 1):
        sequences.append(data.iloc[i:i + sequence_length].values)
    sequences_np = np.array(sequences)
    
    # シーケンスの形状を確認
    logger.info(f"生成されたシーケンスの形状: {sequences_np.shape}")
    
    return sequences_np

5. 依存関係の確認

依存関係が正しくインストールされているか確認するためのコードです。

import importlib

def check_package(package_name):
    package = importlib.util.find_spec(package_name)
    if package is None:
        print(f"{package_name}はインストールされていません。")
    else:
        print(f"{package_name}はインストールされています。")

# 確認するパッケージのリスト
packages = ['tensorflow', 'pandas', 'numpy', 'requests']
for pkg in packages:
    check_package(pkg)
Yodaka

これらのコードを実行することで、問題点を解決し、システムが正常に稼働するようにすることができます。

少数ショット学習について理解を深めるために

Yodaka

以下は少数ショット学習について理解を深めるためには、以下のトピックやリソースです。

1. 基本的な機械学習と深層学習の理解

  • 機械学習の基礎: モデルの訓練や評価、過学習(オーバーフィッティング)や一般化の概念。
  • 深層学習の基礎: ニューラルネットワーク、バックプロパゲーション、オプティマイザー(例:Adam、SGD)など。

2. メタ学習(Meta-Learning)

  • 基本概念: メタ学習の原則や、いかにして少数のサンプルで新しいタスクに迅速に適応するかを学ぶ。
  • 代表的なアルゴリズム: Model-Agnostic Meta-Learning (MAML)、Reptileなどのアルゴリズムの理解。

3. 転移学習(Transfer Learning)

  • 事前訓練モデル: 大規模データセットで訓練されたモデルを少数ショットタスクに適用する方法。
  • ファインチューニング: 訓練済みモデルを少数のサンプルで微調整する方法。

4. プロトタイプネットワーク(Prototypical Networks)

  • 基本概念: 各クラスの「プロトタイプ」を学習し、新しいサンプルをどのプロトタイプに最も近いかで分類する方法。
  • 実装: PythonやTensorFlow/PyTorchでの実装方法の学習。

5. シーネット(Siamese Networks)

  • 基本概念: ペアのデータの類似性を学習するネットワーク。
  • 応用: 類似度学習や二値分類のタスクでの使用法。

6. データ拡張(Data Augmentation)

  • 手法: 少ないデータでモデルを訓練するためのデータ拡張テクニック。
  • 実装: 画像データやテキストデータの拡張手法の理解。

7. 少数ショット学習の最新研究

  • 論文や記事: 最新の研究やレビュー論文を読むことで、少数ショット学習の最前線の技術やトレンドを把握する。
  • カンファレンス: NeurIPS、ICLR、CVPRなどの学会で発表された最新の研究成果に目を通す。

8. 実践的なプロジェクト

  • 実装: 自分で少数ショット学習を用いたプロジェクトを実装することで、理論と実践のギャップを埋める。
  • コード: GitHubやKaggleのプロジェクトを参考にして、実際のデータセットでモデルを訓練し、評価する。

これらのトピックを学ぶことで、少数ショット学習の理解が深まり、実際のタスクに効果的に応用できるようになります。

補足

少数ショット学習のコンテキストでLSTMを直接使用するケースは少ないですが、時系列データやシーケンスデータを扱う特定のシナリオでは関連があります。LSTMが少数ショット学習にどのように役立つかは、その応用場面に依存します:

LSTMと少数ショット学習の組み合わせのシナリオ:

  1. 時系列データの少数ショット学習:
    • 時系列データを扱う少数ショット学習タスクでは、LSTMの長期的依存関係を捉える能力が有用です。例えば、株価の予測や気象状況の予測で、過去の少数のパターンから未来を予測する場合などです。
  2. シーケンスデータのメタ学習:
    • LSTMを用いてシーケンスデータの表現を学習し、その学習した表現を基に新しいシーケンスのタスクに迅速に適応するメタ学習のアプローチが考えられます。
  3. 複合モデル:
    • LSTMと他のネットワーク(例えばプロトタイプネットワーク)を組み合わせることで、シーケンスの特徴を抽出し、それを少数ショット学習に応用することが可能です。

注意点

焦点の違い: 少数ショット学習は特に「新しいクラスやタスクへの迅速な適応」に焦点を当てており、LSTMは「長期依存性のあるデータの処理」に強みを持っています。そのため、一般的な少数ショット学習の文脈では、直接的な関連性が少ないため、他の手法がより一般的に推奨されます。

特定のニーズ: LSTMはシーケンスデータや時系列データの処理に特化しているため、この種のデータを扱わない少数ショット学習タスクでは他のアプローチが適しています。

まとめ

今回は「LSTM(Long Short-Term Memory)モデルを使って予測を行う自動取引システム」についてまとめました。

今後、価格予測のシステムを構築する第一歩にします。

Yodaka

知らないことも多いですが、一つ一つ楽しみながら進めていきます。

今後もこの調子で開発と研究の過程を発信していきます。

-Bot, トレードロジック, 機械学習・データサイエンス