LoginSignup
12
17

More than 5 years have passed since last update.

株価チャートをベクトルに変換するchart2vec(autokerasベース)を作った話

Last updated at Posted at 2019-01-14

今回はchart2vecを作った話です。

株において銘柄の強弱はチャートに現れるのでチャートの分析は非常に重要です。時系列としてではなく図形として視覚的に投資判断をするプレイヤーが多そうなので需要予測に使えるのではないかと思い、これを作りました。

前準備的な話

autokerasの使い方
https://qiita.com/shiibass/items/28ffcaa9aec2799d5691

特徴量抽出器の作り方
https://qiita.com/shiibass/items/c1b7649019c1df965db1

今回作ったもの

チャートを画像データに変換する

株価の日足データは始値、高値、安値、終値の4項目で表すことが多く、Pythonではmpl-financeという超便利ライブラリがあります。https://pypi.org/project/mpl-finance/
その中のcandlestick_ohlcでローソクを生成でき、残りはmatplotlibで描画します。細かいことはgithubを見てほしいですが、抜粋するとこんな感じ↓

    fig = plt.figure()
    ax = plt.subplot()
    plt.xticks(color="None")
    plt.yticks(color="None")
    plt.tick_params(length=0)
    xdate = [
        datetime.datetime.strptime(x, "%Y-%m-%d") for x in chart_data["date"]
    ]
    ohlc = numpy.vstack((date2num(xdate), chart_data[["open", "high", "low", "close"]].values.T)).T
    mpf.candlestick_ohlc(ax, ohlc, width=0.7, colorup='r', colordown='g')
    ax.set_xlim(xdate[0], xdate[-1])
    fig.autofmt_xdate()
    fig.savefig("{}/img/{}".format(DATA_PATH, jpg_name))
    plt.close(fig)

これを実行すると↓みたいなCSVが↓↓みたいな画像に変換できます。

date,open,high,low,close
2015-02-16,190.52002001334,193.9045580982956,189.62712940891217,191.05201340026787
2015-02-19,193.03162976389825,199.16988122028255,192.45049833749204,199.06988122028255
2015-02-20,197.9417428370527,198.6110831926739,193.94584606728242,196.10170918075815

0_label1.jpg

ローソクチャートを使わない人はmpl-financeは不要です。matplotlibなどで自由にチャート画像を生成してください。
私はこの画像に移動平均を加えたり出来高を加えたりしてます。

学習

↑で書いた方法で画像データを4000枚用意しました。サンプルとして2種類に分類するタスクにしてあり、それぞれ1つの確率微分方程式に対応しています。データはgithubに上げてます。例えば↑が片方のラベルAで↓がラベルBです。
2_label2.jpg

学習の仕方は以前書いた記事にまとめました
https://qiita.com/shiibass/items/28ffcaa9aec2799d5691
autokerasを使っています。コードはこれです。


    model = autokeras.ImageClassifier()
    model.fit(train_X, train_Y, time_limit=0.5*60*60)
    print(model.cnn.searcher.history)
    model.final_fit(
        train_X,
        train_Y,
        test_X,
        test_Y,
        retrain=False)
    print(model.cnn.best_model.produce_model())
    path = "model.pkl"
    model.export_autokeras_model(path)

学習結果はこんな感じでした。11個のネットワークを生成し、だんだん損失が小さくなっていくのがわかります。

[
{'model_id': 0, 'loss': 1.3202951815910637, 'metric_value': 0.8827067669172932},
#..略
 {'model_id': 3, 'loss': 0.542041439958848, 'metric_value': 0.9533834586466166},
 {'model_id': 4, 'loss': 0.9012323039351031, 'metric_value': 0.930827067669173},
 {'model_id': 5, 'loss': 1.0478272199252388, 'metric_value': 0.9285714285714285},
# 略
 {'model_id': 9, 'loss': 0.12342515563123016, 'metric_value': 0.9894736842105262},
 {'model_id': 10, 'loss': 0.1919486330296877, 'metric_value': 0.9789473684210526}
]

出来上がったネットワークはこんな感じのいろいろ層が詰まったやつ(ネットワークの結合手順は数字の順番ではないので注意。autokerasを使うとこんなことができるっていうイメージを持ってもらいたいので雰囲気こんな感じです)

TorchModel(
  (0): ReLU()
  (1): BatchNorm2d(3, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (2): Conv2d(3, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (4): ReLU()
  (5): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (6): Conv2d(128, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (7): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (8): ReLU()
  (9): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (10): Conv2d(512, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (11): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (12): GlobalAvgPool2d()
  (13): Dropout2d(p=0.25)
  (14): Linear(in_features=64, out_features=64, bias=True)
  (15): ReLU()
  (16): Linear(in_features=64, out_features=2, bias=True)
  (17): Conv2d(64, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (18): Conv2d(512, 512, kernel_size=(1, 1), stride=(1, 1))
)

予測

学習したモデルで分類として使うのもよいですが、特徴ベクトルを抽出したいです。autokerasのソースを書き換えて、チャートデータをベクトルデータに変換します。
↑のTorchModelで(14): Linear(in_features=64, out_features=64, bias=True)の結果を取り出して↓のように64次元のベクトルに変換できました。

キャプチャ.PNG

コードはこんな感じ

    X, _ = load_dataset("{}/img".format(DATA_PATH))
    test_X = numpy.array(X)
    path = "model.pkl"
    model = autokeras.utils.pickle_from_file(path)
    vec_X = model.predict(test_X[0:2], output_index=-2)
    df = pandas.DataFrame(vec_X)
    df.to_csv("vec.csv", index=False)

ベクトル変換するメリット

画像やテーブルデータ、時系列データなど複数のデータ構造を同時に機械学習する場合はこんな感じのネットワークを作って結合させますか?もちろんいいと思いますが計算量が巨大になるのとうまく最適化させるのが難しそうです。

blog用.png

2vecでベクトル化を前処理として加えることでデータの扱いやすさが格段にアップします↓。XGBoostも使えるようになりますし、クラスタリングして可視化などもしやすくなります。あとは類似チャートの自動検知システムを作ったり、爆上げチャートの分析に使ったり、使い方はいろいろです。

blog用 (1).jpg

発想元資料

今回以下の2つの論文のアイデアを組み合わせるために開発しました。

Deep Neural Networks for YouTube Recommendations

参考にした資料としてはYoutubeのレコメンドアルゴリズムです。投資をやっていなくても読む価値ありまくりの論文です。所属する企業に役立つ論文も多少は読まないとね?
論文↓の中で下図のような異なるデータ構造のデータを結合させたディープラーニングを実装していて、学習性能を高めるためには重要な要素だよなーと思った次第です。
https://static.googleusercontent.com/media/research.google.com/ja//pubs/archive/45530.pdf

キャプチャ2.PNG

Stock Chart Pattern recognition with Deep Learning

チャート形状を認識するディープラーニングです。これは投資をやっていない人にはあまり価値のない論文です。
https://arxiv.org/pdf/1808.00418.pdf

12
17
3

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
12
17