今日も窓辺でプログラム

外資系企業勤めのエンジニアが勉強した内容をまとめておくブログ

日経平均と相関のある経済指数は何か?(1)

今回やること

このページで、Google Cloud Platformを使用してアメリカの株価(S&P 500)が上がるか下がるかを予想する方法を紹介しています。
datalab/FinancialTimeSeriesTensorFlow.ipynb at master · corrieelston/datalab · GitHub

リンク先の記事内では、S&P 500が世界の他の指標とどの程度相関があるかなどを調べているので、今回はこれを日経平均に置き換えて試してみたいと思います。
最終的な野望は、日経平均の上げ下げをある程度予測して、それに基づいて日経レバやダブルインバースを買ってみることですが、まずは地道に行きましょう。

また、当然同じようなことをやっている方は既にたくさんいて、私は特にこちらの方の記事を参考にさせていてだいています。
[TensorFlowで株価予想] 0 - Google のサンプルコードを動かしてみる - Qiita

対象とする経済指数

私は投資初心者であまり詳しくないのですが、なんとなく有名どころとか重要っぽい指標をいくつかピックアップしてみました。

INDEX_LIST = ["N225",   # Nikkei 225, Japan
               "HSI",   # Hang Seng, Hong Kong
               "AORD",  # All Ords, Australia
               "STI",   # STI Index, Singapore
               "GDAXI", # DAX, German
               "FTSE",  # FTSE 100, UK
               "DJI",   # Dow, US
               "GSPC",  # S&P 500, US
               "IXIC",  # NASDAQ, US
               "BVSP"]  # BOVESPA, Brazil

各指標の終値のデータを用意する

早速、先ほど挙げた指数の日ごとのデータをYahooファイナンスからダウンロードしてきて、今回興味のある終値のみを取り出します。
データの操作にはpandasを使用しています。

import numpy as np
import pandas as pd
import os
import urllib.request

class StockData(object):
    def __init__(self):
        self.basedir = "./data/"
        if not os.path.exists(self.basedir):
            os.mkdir(self.basedir)
        self.baseurl = r"http://real-chart.finance.yahoo.com/table.csv?ignore=.csv&s=%5E"


    def download(self):
        # Download historical data for major markets
        for index in INDEX_LIST:
            filename = self.basedir + index + ".csv"
            url = self.baseurl + index
            try:
                with urllib.request.urlopen(urllib.request.Request(url)) as response:
                    message = response.read()
                    with open(filename, "wb") as f:
                        f.write(message)
            except:
                print("Error:", url)

    def get_closing_data(self, days=1000, normalize=False, logreturn=False):
        """ Get closing data for indecis.

        If days is given, return the data for last <days> days.
        If normalize is set to True, then closing value is normalized during the period.
        :type days: int
        :type normalize: bool
        :type logreturn: bool
        :rtype: pandas.DataFrame
        """
        closing_data = pd.DataFrame()
        for index in INDEX_LIST:
            df = pd.read_csv(self.basedir + index + ".csv").set_index("Date")
            closing_data[index] = df["Close"][:days] if days else df["Close"]

        # Reverse the dataframe as CSV contains data in desc order
        # Also, fill empty cells by fillna method
        closing_data = closing_data.fillna(method="ffill")[::-1].fillna(method="ffill")

        # Normalizations
        for index in INDEX_LIST:
            if normalize:
                closing_data[index] = closing_data[index] / max(closing_data[index])
            if logreturn:
                closing_data[index] = np.log(closing_data[index] / closing_data[index].shift())
        return closing_data

エラー処理とかが雑ですが、download()でデータをダウンロードしたあと、get_closing_data()を呼ぶことで終値のデータが得られます。引数daysを与えると、過去days分だけのデータを返します。(デフォルトは1000日分)
normalizeとlogreturnというフラグがTrueのときはそれぞれ正規化をしていますが、まずはその部分は無視してください。

get_closing_dataは最新のデータが末尾に来るように書いてあるので、見た目はこのような形になります。

s = StockData()
s.download()
closing_data = s.get_closing_data()

f:id:kanohk:20160713192630p:plain
STIやFTSEなど、一部同じ値で埋まっているものがありますが、これはダウンロードしたデータにここ数日の値が入っておらず、それを前日の値で埋めて補っているためです。

これをプロットしてあげると、次のようになります。

closing_data.plot(figsize=(20, 15))

f:id:kanohk:20160713193531p:plain

終値を正規化する

正規化して再度プロット

ブラジルのボベスパという指数の値が大きいので、他の指数の動きがよくわからなくなっています。正規化して再度プロットしなおしてみるとこんな感じです。最初に示したコードでは、

s.get_closing_data(normalize=True)

とするとこのデータを得ることができます。
f:id:kanohk:20160713193954p:plain
なんとなく、どの指数も同じようなトレンドで動いているような気がします。

自己相関もプロット

元の記事ではこの後に自己相関のグラフをプロットしていたので、私もその通りにやってみます。

from pandas.tools.plotting import autocorrelation_plot
fig = plt.figure()
fig.set_figwidth(20)
fig.set_figheight(15)

for index in INDEX_LIST:
    _ = autocorrelation_plot(closing_data[index], label=INDEX_TO_DISPLAY_TEXT[index])

f:id:kanohk:20160713194336p:plain
自己相関には全然なじみがないのですが、軽く調べたところ、時系列データが自身の過去のデータとどのくらい相関しているか、ということを表すようです。通常の相関と同じく、絶対値が大きいほど強い相関があります。
横軸のLagというのが、どのくらい過去かを表しています。図を見ると、左側(Lagが小さいほう)の自己相関が1に近くなっているので、どの指数も直近の過去と強い正の相関を持っていることがわかります。

散布図行列を描いてみる

元の記事をさらに先に進めます。
二つの指標をそれぞれ縦軸と横軸に取ると、散布図を作ることができます。このとき点が直線状に分布していると、その2つの指標は相関があるといえます。このような散布図を、すべての指標の対に対してとったものが散布図行列です。
説明するより、図を見たほうが理解できるかと思います。

f:id:kanohk:20160713194953p:plain

ちょっと大きな画像ですが、各セルが2つの指標の散布図となっています。これが直線に近いものほど、相関が強いと言えそうです。
ぱっと見てみると、GSPC、DJI、IXICの3つがそれぞれほぼ直線状な散布図になっており、相関が強いことが見て取れます。
これら3つはS&P500、ダウ30種、NASDAQというアメリカ市場の指数なので、強い相関があるのは当たり前ですね。

他にも、日経平均(=N225)に注目してみてみると、ドイツのDAX(=GDAXI)や先ほど挙げたアメリカの3つの指標と特に強い相関があるように見えます。

このように終値を正規化して遊んでいるだけでも楽しいのですが、終値を単純に最大値で割って正規化しただけでは株価予測のモデリングにはあまり役立たないようです。(なぜ?)
記事では、続いて実際のモデル化にも役に立つようなデータの作り方が紹介されているので、私も同じように見ていこうと思います。

ちょっと長くなってしまったので、次回へ続きます。。
日経平均と相関のある経済指数は何か?(2) - 今日も窓辺でプログラム