株の自動売買アルゴリズムを強化学習でつくる

個人投資家でも株式市場にアルゴリズムを導入する人が増えてきました。特に、最近ではカブコムAPIの登場により、簡単にアルゴリズムトレードができるようになりました。
https://kabu.com/api/kabucom_api.html

仮想通貨市場でアルゴリズムトレードが人気でしたが、これからは株式市場に流れるプレイヤーも増えてくるでしょう。アルゴリズムトレードは技術を追究したいプログラマーには非常におすすめです。ゴールドマンサックスやモルガンスタンレーなどの海外の超大口投資家は本気で個人投資家を負かしにくるので、プログラミング好きほどはまると思います。
注意したいのは個人投資家は大口を負かそうとしてはいけません。自分が負けないことだけを考えて生き延びるのがせいいっぱいだと思います。

今回は強化学習を紹介します。

# 強化学習の考え方

強化学習は状態$s$で行動$a$を選択していって報酬$r$の総和を最大化するように学習していく、とよく表現されることが多いです。私の解釈では状態$s$において行動$a$を選択する価値を予測するという機械学習タスクという認識です。その価値は教師ラベルとして事前についているというよりかは、報酬の割引によって再帰的に見積もられた値なので、ちょっと特殊な回帰問題くらいな感じです。
今回作った強化学習では状態が板の状況、行動は買うか買わないかの2択としています。
コード全体はここにあります。本番で使っているデータと特徴量変換はgithubにあげておらず、テスト用のものになっています。
https://github.com/shiibashi/daytra

# 状態s
板の状況というのは株の取引き状況がわかる以下のようなもののことです。
![AnyConv.com__video_2020-03-30_very_small.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211078/5aa10065-296f-5340-5ff9-1912df24fb98.gif)

これを画像として読み込むのではなく、OCRで構造化データに変換して強化学習の特徴量にします。OCRの開発については過去の記事で記してあります。
https://qiita.com/shiibass/items/20235d3952a804e1a1e9

データの変換は下図にまとめてあるように、OCRでCSVに変換したあと、ほかのアルゴリズムがどういう動きをするかを推定して特徴量としています。"ほかのアルゴリズム"というのはこの板でぴこぴこ点灯しているのが他社のアルゴリズムによるもので、これらがどういう挙動をするのかを推定するような感じです。

![blog用 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211078/cf12fdad-97a5-bc9e-f494-603e6a354dfd.jpeg)

# 学習させる環境
デイトレードの強化学習をしたいため、その日で持ったポジションは必ずその日のうちに決済するようにします。買いのみで空売りはしません。買って売っての差分が利益になりますので、その総和が最大になるように学習していきます。税金や手数料は適当に計算にいれます。
その日のうちにポジションをフリーにする理由としては、長期的な投資にしてしまうと企業の業績に依存してしまったり、短期的なトレンドによって成績が変わってしまいますが、デイトレードではシンプルにアルゴリズムの勝負に持っていけるため、サイエンスの活躍の幅が増えるからです。
環境は事前に録画してある数か月間分の板のデータを読み込ませて単位時間ごとに時間を進めていってその瞬間の板を取り出して、買うか買わないかの選択をしていくというもので、コードにすると以下のようになっています。self.itrが環境内で用いている時間、self.datasetが数か月間の板の録画データということになります。

```python
class Env(object):

    def __init__(self, df):
        self.dataset = df
        self.state = None
        self.itr = None
        self.time = None
        self.position = None
        self.fee = 0#1
        self.gap = 0#5
        self.time_decay_param = 10

        self.trade = None
        self.initialize()

    def step(self, action):
        reward = self.calc_reward(action)
        self.itr += 1
        next_state = self._state()
        done = self.done_flag()
        ymd_index = self.dataset["ymd_index"][self.itr]
        info = {"weight": self.time_decay(ymd_index)}
        self.time = self.dataset["hms"][self.itr]
        self.ymd = self.dataset["ymd"][self.itr]
        return next_state, reward, done, info

    def _state(self):
        state = feature_converter.convert(self.dataset, self.itr)
        if self.position[0] == Action.STAY:
            position = [0]
        elif self.position[0] == Action.BUY:
            position = [1] 
        else:
            raise
        new_state = state + position
        return new_state
```

# 報酬r
報酬は買って売っての差分を設定していなくて、損益が出た場合には2倍にしてペナルティを大きくしています。コードだとこうなっています。

```python
        while not done:
            action = agent.get_action(state)
            next_state, reward, done, info = env.step(action)
            reward = reward * 2 if reward < 0 else reward
            one_batch = (state, action, reward, next_state, done, info)
            state = next_state
            history.append(one_batch)
```

# 学習方法
強化学習の学習方法はRAINBOWを使います。RAINBOWのうちdistributed RLは実装していません。学習に使うデータはコード2413の銘柄で、トレードする銘柄もこれ一本に絞ります。

# 評価方法
オフライン評価としては持っているデータを学習データと評価データに分けてバックテストを行います。オフライン評価で利益をとれていたら、本番環境で資産を投下して市場に参戦します。
オフライン評価では比較として3つのアルゴリズムを作っています。
https://github.com/shiibashi/daytra/tree/master/script/trader
に強化学習を含めた4つのアルゴリズムがあり、
- baseline・・初回に買ってずっとホールドする(デイトレードではありません)。悪決算や不祥事などが発覚すると避けられないので実用性は低い。もちろん長期投資であればずっとホールドしますが、今回作ろうとしている自動売買の趣旨からは外れています。
- onlybuyday・・毎日寄りで買って引けで売るアルゴリズム。長い陽線を形成しながら上昇していくときのみ有効。ダウントレンドでは勝てないアルゴリズムなので実用性は低い
- rulebased・・移動平均線などで適当に売買ルールを作ったアルゴリズム。人間が考えたルールなので市場で勝てるわけがない。
- rl・・強化学習アルゴリズム

githubにあげているテスト用のデータで学習、評価するとこのようになりました
左から順にアルゴリズム名, 利益(手数料なし), 利益(手数料あり), 取引回数です。
こんな感じで実験しています。

```bash
trade report,  rl 0 0 0
trade report,  baseline 15.0 10.0 1
trade report,  onlybuyday 150.0 100.0 10
trade report,  rulebased -480.0 -560.0 16
```

# 推論について
強化学習モデルで推論すると状態$s$において行動$a$を選択する価値が出力されます。価値のことをQ値と呼ぶことにすると、これが高い方が有利な状況（報酬を得るという点で）、低い場合は不利な状況ということになりますので、これに閾値を設けてそれ以上であれば買いという判定をすることにしました。考え方としては分類の機械学習で閾値を設定するのと同じです。下図でいうと推論結果がbuy_tauより高ければ買いで、それ以下は買わない(ポジションを持っていたら決済する)というルールになります。buy_tauはソースコードだと
https://github.com/shiibashi/daytra/blob/master/script/trader/rl_trader.py
で設定しています。

![blog用 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211078/e7a11438-ca60-ca8d-e04d-92d880d4ce66.jpeg)

# このアルゴリズムの特徴
このアルゴリズムの強みの一つは強化学習を使っていることです。過去にいくつか研究した結果、株価でシンプルな時系列予測は通用せず、その１歩先の予測をしないと勝てないというのが私の結論です。感覚としては、単純な時系列予測のアルゴリズムを殺すアルゴリズムに負かされるという感じです。
強化学習では未来の報酬を割り引いて利益が発生していなくても現在の価値を評価できるということで、将来上がるシグナルを検知したら先に買っておくという戦略がとれることです。実際、株の取引では大口の買い集めというのが重要になってきますので強化学習との相性は非常に良いといえます。
強化学習よりももっと強い特徴としては板の録画データを大量に持っているということです。株価データは始値、終値、高値、安値くらいであればスクレイピングでもすれば取得できますし、日中の株価の推移に関しては買えば手に入ります。しかし板の録画データは持っている人はそうそういないでしょうから、このデータを持っていない人がこのアルゴリズムを負かすのは容易ではないということです。ちなみに、録画データはこつこつと毎日録画してためているだけですので誰でもできます。

# 次回テーマ：運用について
次回のQiitaでこの強化学習モデルをどう使っているかの運用方法について書きます。↓のようにLINEで運用するところまで記事にします。

![IMG-0445.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211078/6775970c-0a5e-e344-36c8-a782c1c9f636.png)

# 最後に
この記事を読んで機械学習エンジニアが株式市場に参戦してくれると嬉しいです。共有できるノウハウを公開しあって各自の成績向上につながればいいサイクルができあがると思います。