DQNで機械学習した人工知能がBitcoinをシストレして月700万円儲けるまでの話（失敗）

昨日の記事は @orzngo さんの「[Slack上で動作するチャットシステムの構築](https://qiita.com/orzngo/items/2042bdc326b825745357)」でした。

@dogwood008 と申します。普段は プログラミング教育サービス [N予備校](https://www.nnn.ed.nico/pages/programming/) のバックエンドを担当しています。

## TL;DR

- Bitcoinの過去の値動きを機械学習させた
- 学習済みモデルを使用して、エージェントにシステムトレード（コンピュータによる自動売買）をさせた
    - 現実の通貨ではなく、シミュレーション
- 訓練データの2017年9月の1ヶ月での損益は、 `+714.0万円` 
    - 上昇相場（2017年8月）では `+3577.7万円` 
    - 下降相場（2017年3月）では `-44.0万円`
- 結論としては、今回の試みは失敗
    - いくつかの要因が考えられる

下図は、<font color="green">その時点での損益（緑色、左軸）</font>と<font color="blue">その時点でのBTCJPYの値（青色、右軸）</font>をプロットした図です。本記事で紹介した手法で学習したエージェントがシステムトレード（自動売買）した際のシミュレーション値です。
![2017_Sep.png](https://qiita-image-store.s3.amazonaws.com/0/28930/21eb4542-be64-740a-2e5f-3253b27b1d97.png)


## 免責事項

```
• 本記事の内容は、著者個人が趣味の時間に自発的に行ったものです。著者が所属する会社または団体の監督指導の下に行ったものではありません。アドベントカレンダーとして表示されるため、所属する会社または団体の発表のように見えることがありますが、その会社または団体は本記事の内容について、一切関知しておらず、なんら責任や関連はありません。
• 本記事の内容は、著者個人による見解であり、所属する団体、組織、会社、その他一切の枠組みによる公式見解ではありません。また、それらは本記事に対する責任や関連も一切ありません。
• 本記事の内容は、機械学習に関する情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。
• 本記事の内容を参考にして、投資の判断を行わないでください。また、本記事の内容が正確であることを、著者は一切保証しません。未来の出来事に対する予想も、あくまで予想であり、その時々の状況によって変わりうることにご注意ください。
• 投資を行う際には、投資を行う本人のみの判断と責任において行ってください。
• 仮に投資に失敗し、投資を行った者の資産が減ったり債務を負ったりしても、著者はなんら責任を負いません。
• その他、本記事を参考にしたかどうかに関わらず、投資の失敗や機会の損失等を含むいかなる不利益が何人に生じたとしても、著者はなんら責任を負いません。
```

## 機械学習の知識は0から始めた

大学で少しかじっていたので、0からというと若干大げさですが、あんまり覚えていないのでほぼ0からでした。いろんな本を読みまわったり、オンラインの学習コースを受講したりしました。個人的にわかりやすかったのは以下の2つです。

- [Machine Learning Engineer Nanodegree - Udacity](https://www.udacity.com/course/machine-learning-engineer-nanodegree--nd009)
- [ゼロから作るDeep Learning
――Pythonで学ぶディープラーニングの理論と実装](https://www.oreilly.co.jp/books/9784873117584/)


まだまだ勉強途中のため、本記事には誤りが含まれるかもしれません。その際はコメントでご指摘いただけると幸いです。

## DQNの使用

### 概要

このシステムトレードを行うエージェントには、DQN (deep Q-network) と呼ばれるものを使いました。詳細はここでは述べませんが、ざっくりいうと、以下のような特徴があります。

- Q学習という手法がある
    - 強化学習の一種で、学習時に教師データを与えない
        - ある `状態` のときにある `行動` を取った時にどのような `報酬` があるかをエージェントに教える
        - これによりコンピュータが自分で学習する
        - `状態` `行動` `報酬` はQ学習における用語
    - もっと詳しく知りたい方は、文末の参考文献をご覧ください
- そのQ学習と深層学習を組み合わせたものがDQN
    - 例えば、ブロック崩しのゲームであれば、その画面を入力に使える
    - 「何が自機で何が敵で、何がブロックなので壊せて…」というように、環境に関する情報を与えない
- よくわかんない人は、「機械学習のやべーやつ」と思ってもらったらOKです

### DQNを選択した理由

教師データの付与が不要な点、実際にFXで行われた（[Deep Q-LearningでFXしてみた](http://recruit.gmo.jp/engineer/jisedai/blog/deep-q-learning/)）方がいらっしゃった点、名前がおもしろいなと思った点です。

また、本内容は[ドワンゴ社内エンジニアLT大会（社外向け）](https://dwango.connpass.com/event/71978/)で発表しました。その際に仮題の提出を求められ、ちょうどDQNの勉強をしていたため、「仮だし、DQNで～ってつけておくか」としてしまいました。それがそのままconnpassでの発表タイトルとして出てしまったので、勝手に変えてしまってはDQNでの自動取引を目当てに来ていただいた方に失礼と思い、そのままDQNで進めました。

## 機械学習に使用したもの

ヒストリカルデータにはcoincheckのBTCJPYの値を使用しました。
2017年9月1日～9月30日の1分足が[kaggleで配付](https://www.kaggle.com/mczielinski/bitcoin-historical-data)されています。
これを1時間足へ変換し、各足の終値の値をその時のBitcoinの売値/買値としました。

下記の図は、使用したヒストリカルデータをグラフに起こしたものです。x軸は日時、y軸はその時のBTCJPYの値です。y軸の単位は万円です。

![2017_Sep_BTCJPY.png](https://qiita-image-store.s3.amazonaws.com/0/28930/fe0524b5-a698-7f52-5b7a-adfb5d642842.png)


### ソースコード

自動取引のシミュレーションを行うエージェントについては、実はFX用に作っているものがありました。今回はそれをBitcoin用に一部改造して使いました。
https://github.com/dogwood008/DeepFX

### GPU付きのインスタンス

[Paperspace (非アフィリンク)](https://www.paperspace.com)でインスタンスを借りて使いました。その時の詳しいやりかたは [クラウドでGPUを使った機械学習を安価で行う（Paperspace）](http://blog.dogwood008.com/entry/paperspace_use)をどうぞ。

## 機械学習にかかった時間

1日くらい。学習で与えるデータを1ヶ月に絞ったのは、これを短くしたかったため。インスタンス借りている間はずっと課金され続けるので、学習時間が短くすむようにしました。

## シミュレーション

### 条件

以下の条件のもと、前述のヒストリカルデータを使用して学習を行いました。

- ヒストリカルデータについて
    - ある時点におけるBitcoinの売値、買値は同一
    - スプレッドは存在しない
    - 手数料も0円
    - Bitcoin取引の利益にかかる税金は、源泉徴収されない
        - ＝取引の際に税額が天引きされない
    - エージェントは直近48時間分のBTCJPYの値を参照できる
        - 未来の値は（当然だが）参照できない
- 報酬の計算式は次の通り
    - （その時点でのBTCJPYの値）＊（保持しているBTCの数）＋（手持ちの現金）－（初期の現金）
- 初期の現金は1000万円
- 初期のBTC保持数は0
- 取引は現物のみ
    - BTCを借りて売りから入ることはできない
    - 保持しているBTCの数以上は売却できない
    - 購入したら即座に現金が減少する
    - 売却したら即座に現金が増加する
- 1時間毎に、売り、買い、保持のどれかをエージェントが選択する
    - 1度に取引できるBTCの数は10
        - そのため、エージェントがとれる選択肢は次の3つ
            - 10BTCを購入
            - 10BTCを売却
            - 何もしない

### 2017年9月（学習データ）

![2017_Sep.png](https://qiita-image-store.s3.amazonaws.com/0/28930/21eb4542-be64-740a-2e5f-3253b27b1d97.png)

<font color="green">左y軸（緑色グラフ）の損益の単位は `万円` </font>、<font color="blue">右y軸（青色グラフ）のBTCJPYの単位は `円` </font>です。最大で-900万円程損失を抱えますが、その後700万円超の利益へ転じています。ただ、BTCJPYと報酬のグラフの傾きが同じで、少し不穏な空気を感じます。後述しますが、このときの悪い予感は的中します。

### 2017年8月（上昇相場）

![2017_Aug.png](https://qiita-image-store.s3.amazonaws.com/0/28930/7e0b2653-6788-6de9-d59d-0293f0751268.png)

あれ？報酬（損益）のグラフは？と一瞬見失いそうになりますが、よく見ると開始直後に緑色のグラフがいて、あとは青色と同化していますね。上昇相場では報酬のグラフはぴったりとBTCJPYにひっついています。

### 2017年3月（下降相場）

![2017_Mar.png](https://qiita-image-store.s3.amazonaws.com/0/28930/52226eb6-af11-56b2-dd5f-978eb60207dc.png)

こちらも序盤は分かれていますが、ある時点から報酬とBTCJPYのグラフがひっついてしまっています。


## 考察

### 機械が学習したものは何だったのか

下図をご覧ください。<font color="red">赤いグラフ</font>が上にはねている部分が、「買い」の注文をしたところです。序盤に購入し、一回BTCJPYが下がったところで再度購入しています。（8月のグラフは一瞬下にはねており、そこが「売り」の注文をしたところですが、手持ちのBitcoinの数が0のため、注文が通りませんでした。）


![2017_Sep_Pob.png](https://qiita-image-store.s3.amazonaws.com/0/28930/313e36de-c621-111d-354e-8052a0e5d0ad.png)

![2017_Aug_pob.png](https://qiita-image-store.s3.amazonaws.com/0/28930/ecfcfdd7-9677-6e7c-67ad-fc8d61e43cc1.png)

![2017_Mar_pob.png](https://qiita-image-store.s3.amazonaws.com/0/28930/78da8752-2d50-ffa4-61da-fb08907cc0f5.png)



この結果を見るにあくまで推測ですが、機械が学習したのは **「序盤に適当に購入して、ガチホールドしておき、もしBTCJPYが下がればナンピン（※）しておけば適当に儲かる」** ということなのではないかと思います。私が機械に期待していた取引は、「短期でBitcoinの売買を繰り返して利益を積み重ねる」ような動きでした。その観点からいうと、今回の試みは失敗だったということになります。

※ナンピン…この場合、BTCJPYの価値が下がった時に再度購入することで、BTCの平均取得価格を下げることをいいます

### 「Bitcoinのシステムトレードを行うエージェント」という題材

今回学習に使用した1ヶ月のBTCJPYのデータは、Bitcoinの値動きを如実に表したもの、とは言えません。皆様がご存じの通り、現在のBitcoinの価格は暴騰した後、乱高下しています。したがって、それを1月でぶつ切りしたものを学習してもBitcoin取引のためのデータとしては適切ではありませんでした。

一方、株やFXを考えてみましょう。株は平日の09:00-15:00（うち、1時間昼休み）、FXも土日を除く早朝〜深夜までです。つまり、どちらも5営業日の後、取引が停止されます。未検証なので、確実なことは何も言えませんが、周期性のあるデータ、例えば1週間、1ヶ月、1年等のヒストリカルデータを使って学習すると、異なった結果が得られるかもしれません。

## 今後の課題

Bitcoinだけでなく、株やFXでも試行してみたいと思います。また、前述したとおり、1ヶ月だけではなく、周期性のあるヒストリカルデータで試験してみたいです。

今回はDQNを使用しましたが、それ以外の選択肢も考えるべきです。また、モデルに関しても深く考察はできていません。どこかの記事で、DQNとLSTMを組み合わせる、といった手法を目にしたので、可能ならチャレンジしたいと思います。

## 参考にさせていただいたサイト、記事

- [強化学習入門 ～これから強化学習を学びたい人のための基礎知識～](http://blog.brainpad.co.jp/entry/2017/02/24/121500)
- [ゼロからDeepまで学ぶ強化学習](https://qiita.com/icoxfog417/items/242439ecd1a477ece312)
- [Pythonではじめる強化学習](https://qiita.com/Hironsan/items/56f6c0b2f4cfd28dd906)
- [これさえ読めばすぐに理解できる強化学習の導入と実践](https://deepage.net/machine_learning/2017/08/10/reinforcement-learning.html)
- [OpenAI GymでQ学習してみた](http://www.jonki.net/entry/2017/01/03/214138)
- [Kerasで最短で強化学習（reinforcement learning）する with OpenAI Gym](https://qiita.com/kazetof/items/3c33f823be178d97f904)
- [[Python]強化学習(DQN)を実装しながらKerasに慣れる](https://qiita.com/yukiB/items/0a3faa759ca5561e12f8)
- [[Python] Keras-RLで簡単に強化学習(DQN)を試す](https://qiita.com/inoory/items/e63ade6f21766c7c2393)
- [DQNをKerasとTensorFlowとOpenAI Gymで実装する](http://elix-tech.github.io/ja/2016/06/29/dqn-ja.html)