機械学習(サポートベクターマシン)を使って株の売買シミュレーションを行う

  • URLをコピーしました!
目次

はじめに

機械学習の仕組みを使って、株の自動売買のシミュレーションをしてみます。モデルはサポートベクターマシン、指標はRSIを用いることとします。

シミュレーション条件

株価のデータは既に取得済みとします。テストデータは直近(2023/05/01まで)の2年間とします。学習データの生成期間はそれ以前の5年から15年、移動平均の期間も5日から50日と変動させ、2年で10万円の資産が増えるかどうか、を記録することとします。

サンプルコード

以下にサンプルコードを記載します。サポートベクターマシン(SVM)の主要なパラメータについて説明します。SVMでは主に次の二つのパラメータが重要です:

  • C:誤分類に対するペナルティ(Cが大きいほど誤分類を許さない)
  • gamma:決定境界の複雑さ(gammaが大きいほど境界は複雑になる)

ここでは、sklearnのGridSearchCVを用いて、これらのパラメータの最適な組み合わせを見つける例を示します。この例では、Cとgammaのそれぞれについて複数の値を試し、クロスバリデーションを用いて最適なパラメータを選択します。

import sqlite3
import pandas as pd
import numpy as np
from sklearn import svm
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score
from ta.momentum import RSIIndicator

# SQLiteデータベースに接続
conn = sqlite3.connect('stock_data.db')
cur = conn.cursor()

# 全ての銘柄を取得
tickers = cur.execute('SELECT DISTINCT ticker FROM stock_price').fetchall()

results = pd.DataFrame(columns=['ticker', 'C', 'gamma', 'accuracy', 'final_money'])

# 各銘柄について処理
for ticker in tickers:
    ticker = ticker[0]
    
    # 銘柄のデータを取得
    df = pd.read_sql(f'SELECT * FROM stock_price WHERE ticker = "{ticker}"', conn)
    df['date'] = pd.to_datetime(df['date'])
    df = df.set_index('date')

    # RSIを計算
    rsi_indicator = RSIIndicator(close = df["close"])
    df['rsi'] = rsi_indicator.rsi()

    # 株価の変化率を計算し、その符号(上がるか下がるか)をラベルとする
    df['target'] = np.sign(df['close'].pct_change().shift(-1))

    # 学習期間とテスト期間を設定
    train_start_date = '2006-05-01'
    train_end_date = '2021-05-01'
    test_end_date = '2023-05-01'

    # 学習データとテストデータに分割
    train_df = df[train_start_date:train_end_date]
    # NaNを前後の値で補完
    train_df = train_df.fillna(method='ffill').fillna(method='bfill')

    test_df = df[train_end_date:test_end_date]
    # NaNを前後の値で補完
    test_df = test_df.fillna(method='ffill').fillna(method='bfill')

    # データを正規化
    scaler = StandardScaler()
    train_scaled = scaler.fit_transform(train_df[['close', 'rsi']])
    test_scaled = scaler.transform(test_df[['close', 'rsi']])

    # サポートベクターマシンでモデルを学習
    parameters = {'kernel':('linear', 'rbf'), 'C':[1, 10], 'gamma':[0.1, 1]}
    svc = svm.SVC()
    clf = GridSearchCV(svc, parameters)
    clf.fit(train_scaled, train_df['target'])

    # テストデータで予測
    test_df.loc[:, 'prediction'] = clf.predict(test_scaled)

    # 精度を計算
    accuracy = accuracy_score(test_df['target'], test_df['prediction'])

    # シミュレーションで資金を計算
    money = 100000  # スタート時の資金
    shares = 0  # 株式の保有数
    for i in range(len(test_df)):
        # 予測による売買
        if test_df['prediction'].iloc[i] == 1:
            shares += money // test_df['close'].iloc[i]
            money %= test_df['close'].iloc[i]
        elif test_df['prediction'].iloc[i] == -1 and shares > 0:
            money += shares * test_df['close'].iloc[i]
            shares = 0

    # 最終的な資産を計算
    final_money = money + shares * test_df['close'].iloc[-1]

    # 結果をデータフレームに追加
    results = pd.concat([results, pd.DataFrame({'ticker': [ticker], 'C': [clf.best_params_['C']], 'gamma': [clf.best_params_['gamma']], 'accuracy': [accuracy], 'final_money': [final_money]})], ignore_index=True)
# 結果をデータベースに保存
results.to_sql('svm_rsi_result', conn, if_exists='replace')

# 接続解除
conn.close()

このコードでは、全ての銘柄コードについてサポートベクターマシンモデルを訓練し、最適なCとgammaのパラメータをグリッドサーチとクロスバリデーションで選択します。それぞれの銘柄について、最適なパラメータとその時のテストデータに対する精度を計算し、結果をデータフレームに保存します。

実行結果

上記のシミュレーション結果です。上位20社を掲載します。

企業名Cgammaaccuracy最終金額
INPEX10.10.5214724¥199,456
ヤクルト10.10.5255624¥188,560
NTT10.10.5316973¥162,443
第一三共10.10.4969325¥161,583
ソニーG1010.5337423¥152,092
東京海上10.10.5276074¥151,525
三菱重10.10.4703476¥146,625
日立110.5071575¥144,928
SOMPO10.10.5276074¥137,992
丸紅1010.4846626¥135,478
住友商10.10.4785276¥131,495
JR東海10.10.5603272¥131,495
キーエンス100.10.5214724¥129,940
伊藤忠10.10.5316973¥129,484
ファナック10.10.5276074¥126,624
アステラス100.10.5194274¥124,628
武田10.10.4989775¥124,192
積ハウス10.10.5071575¥123,826
豊田織100.10.5276074¥122,900
キヤノン110.5214724¥121,812
シミュレーション結果

まとめ

サポートベクターマシンとRSIの組み合わせでシミュレーションを作成しましたが、今回の組み合わせではマイナスの結果が4割弱存在することとなりました。閾値や学習期間の設定などのバリエーションを増やして分析を繰り返すべきではありますが、本モデルは計算時間を要するためある程度予測のもとパラメータ決定を行うことが重要そうです。

バーマン
プロダクトマネージャー
ソフトウェア開発に長く従事しています。
・機械学習のサンプルコード作成
・生成型AIから調べたことのまとめ
・これまでのビジネスで経験したことのまとめ
を記事として作成させていただいています。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次