ストックドッグ

KatoTakahiro。金融系の会社で働くSEが株やPython、その他諸々について書いています。サービスも運営してます→http://fmbrain.work

PandasのデータをSQLite3で保存する

スクレイピングしたデータをどうすればいいかわからない問題発生

株価データ等をYa〇〇〇ファ〇〇〇〇などからスクレイピングして、今まではCSVファイルでローカルのディレクトリに置いていました。

言ってしまえば、スクレイピングして放置状態でした。

データを使用するときはCSV形式なので、今まではそれが都合良かったのですが...

毎回毎回スクレイピングするのは相手方のサーバーに申し訳ないので、そろそろデータベースで管理したほうがいいかなぁ、と思うようになりまして。

データベースで管理すれば、サイトが更新されたデータ分だけを拾って、データベースを更新するだけで済むので、かなり時間も節約できますし。

そこでSQLite3を勉強していたのですが、はてさてpandasのDataFrame形式はいかにしてDBに放り込むのか。


少し調べるとpandasでできるらしいぞ、と。

SQLiteに放り込むCSVファイルはこんな形式。

f:id:doz13189:20170322005408p:plain


コードを以下に貼ります。

import sqlite3
import pandas as pd


#pandasでcsvファイルを読み込む
df = pd.read_csv("code_1332.csv")
df.columns= ["Date", "Open", "High", "Low", "Close", "Volume", "Adj Close", "Number"]

#db作成
dbname = "code.db"

#dbコネクト
conn = sqlite3.connect(dbname)
c = conn.cursor()

#dbのnameをcode_1332とし、読み込んだcsvファイルをsqlに書き込む
#if_existsでもしすでにcode_1332が存在していても、置き換えるように指示
df.to_sql("code_1332", conn, if_exists="replace")

#作成したdbを見てみる
select_sql = 'select * from code_1332'
for row in c.execute(select_sql):
    print(row)

conn.close()

出力を見てみる。

f:id:doz13189:20170322004401p:plain

SQLite3に書き込まれ、DBが作成されています。

pandasって万能やなぁと今日も感じた次第であります。

以上報告終わり!なのですが...


他のシストレやる方たちはどのようにデータを集めて保存しているのですか?

もっと効率良い方法があるなら教えて欲しいです。

もしよければコメント下さい、お願いしますm(_ _)m

Yahooファイナンスの株価予想ページをScrapyでクローリング・スクレイピング

目次

本日やること

Yahooファイナンスでは、毎日アナリスト的な人たちが株価予想を行っています。
今回は、そのページをScrapyでクローリングしながら、各アナリストたちの予想をスクレイピングして、ファイルに保存します。

info.finance.yahoo.co.jp


完成予定ファイル

こんな感じのページを…

f:id:doz13189:20170321184350p:plain

こんな感じのファイルにまとめます!

f:id:doz13189:20170321184425p:plain

必要な環境

python3
scrapy
jq
ubuntu(OSは自由)

なぜscrapy?

scrapyはクローリング・スクレイピングを行うためのライブラリです。
ライブラリの記述ルールを覚えてしまえば、とてもシンプルにクローリング・スクレイピングを行うことができます。

分析等を行うには大前提としてデータが必要です。
データは様々なサイトから集めてくると思うのですが、個々のサイトごとにコードを書いていては大変ですし、また管理の手間も増えます。

scrapyでスクレイピングを行えば、トータル的に無駄が省けてハッピーということです。

Python以外にはあまりスクレイピングのためのライブラリはないようなので、scrapyをバンバン使って、無駄という無駄を省きパイソニストのメリットを最大限に活かしましょう!笑

スクレイピングの流れ

スクレイピング対象のサイトのHTML構成を確認。
scrapyでサイトからスクレイピング
以上!!!(めっちゃ簡単)

Scrapyのインストール

pip install scrapy

Scrapyプロジェクトの作成

scrapy startproject mypredict

Ubuntuで言う端末、Macで言うターミナル、Windowsで言うコマンドプロンプトに上記のコードを打ちましょう。

これでScrapyのプロジェクトが作成されます。
このコマンドを打つと、mypredictというファイルが作成されます。
以降、このフォルダの中で作業を行います。

念の為、ファイル構成を確認しておきましょう。

f:id:doz13189:20170321185616p:plain

中には、Scrapyの設定を記述してあるファイルやスクレイピングした内容を検証するためのファイルがありますが、今回は使用しません。

では、mypredictに移動します

cd mypredict

基本的には、作業はこの階層で行います。

Spiderの作成

scrapyでは、スクレイピングをするためのルールをこのspiderに記述します。
そのため、スクレイピングを行うサイトごとにspiderを作成するイメージです。

スクレイピングをするにはサイトごとに異なるページ構成を考慮する必要があります。
class名やid名などサイトによって使用しているものが異なるので、そういったサイトの個別のルールをこのspiderに記述します。
※ページ内容のダウンロード等は他のファイル(すでに用意されている)

まず、spidersフォルダの中にpredict.pyというファイルを作成します。
このファイルがクローリング・スクレイピングするファイルとなります。

今回作成するファイルはこれだけです。
このファイルで全ての処理を行います。
記述するコードも30行にもいきません。

※注意、ファイルを作成するのはspidersの中ですが、作業をするのはあくまでもmypredict直下です。scrapy.cfgがある階層です。

とりあえず、predict.pyというファイルだけ作成して、そのままにしておきます。

スクレイピングするサイトを確認

先ほど貼った画像と同じです。

f:id:doz13189:20170321184350p:plain


この予想一覧を上から順にクローリングしていき、URLをたどっていきます。

最終的には、このページ内にある全ての個別の予想ページの中身の文章をスクレイピングしていきます。

f:id:doz13189:20170321190701p:plain


ここでクローリングとスクレイピングの意味を確認しておきます。

私もそこまではっきりと認識しているわけではなくて、ニュアンスで使っていますが...

クローリングはサイトの情報を閲覧する

スクレイピングは、閲覧している情報をダウンロードしてくること

こんな感じだと思います、以降このような意味でクローリング・スクレイピングという言葉を使っていきます。

スクレイピングはじまるよー

ではまず、予想トップページをスクレイピングしてみましょう。
この予想トップページから個別ページに繋がるURLを拾ってくるのが目的です。
以下のコードを、ちょっと前に作成してほったらかしにしているpredict.pyに記述します。

import scrapy


class PredictSpider(scrapy.Spider):
	#predictはSpiderの名前。spider実行時に入力する。
	name = "predict"

        #必ず必要なコードです
     #相手サーバーに配慮するために、スクレイピングの間隔に1秒入れます
        custom_settings = {
            "DOWNLOAD_DELAY": 1,
        }

	#スクレイピングを行う際に一番最初にクローリングするページ
	start_urls = ["http://info.finance.yahoo.co.jp/kabuyoso/article/"]
	
	def parse(self, response):

		#Google Chromeの検証等でページの構成を確認すると。
		#URLはHTMLのh3タグのクラス st02の下に格納されていることがわかる。
		for href in response.css("h3.st02 a::attr('href')"):
			
			#相対URLから絶対URLに変換
			url = response.urljoin(href.extract())

			#スクレイピングした内容を確認
			print(url)

ちなみに、ページ構成のスクショは以下。

こればっかりはページのHTMLを確認しながら自分で地道にたどっていくしかないです。

f:id:doz13189:20170321190913p:plain


先ほどのコードを実行してみます。

mypredict直下で以下のコードを打ちます。

scrapy crawl predict

こんな感じでURLがリスト形式で表示されれば成功です。

f:id:doz13189:20170321191206p:plain


さて、これでたどるURLを入手することができました。
次にこのURLを辿って、ページの中身をスクレイピングします。
先ほどのコードを少し変更し、さらに個別ページをたどるコードを追加しています。

import scrapy


class PredictSpider(scrapy.Spider):
	name = "predict"

        custom_settings = {
            "DOWNLOAD_DELAY": 1,
        }

	start_urls = ["http://info.finance.yahoo.co.jp/kabuyoso/article/"]

	def parse(self, response):
		for href in response.css("h3.st02 a::attr('href')"):
			url = response.urljoin(href.extract())
			
			#ここから下が追加分
			#スクレイピングしたURLをたどるためにparse_topicsに投げる
			yield scrapy.Request(url, self.parse_topics)


	def parse_topics(self, response):
		#個別ページのHTML構造を確認する
		#h3タグのクラスst02にタイトルが格納されていることがわかる
		title = response.css("h3.st02 ::text").extract_first()

		#本文はdlタグのクラスmarB20に格納されていることがわかる
		#これを::textで抽出するとbrタグも含めまれて上手くスクレイピングできない
		#xpathのstring()を使用すると、うまい具合にスクレイピングすることができる
		body = response.css("dl.marB20").xpath("string()").extract()

		#辞書形式で格納する
		yield {
			"title" : title,
			"body" : body
		}

先ほどと同じように、たどるページ先のHTML構成を確認しておきます。

f:id:doz13189:20170321191511p:plain


さて実行してみます。

Scrapy crawl predict

実行結果はこちらです。

f:id:doz13189:20170321191620p:plain

スクレイピングが成功していたら、何かしらの文字列が表示されると思います。

スクレイピング内容をファイルに保存

とても簡単です。

#-oはファイルに保存する
#predict.json、ここは自由
#保存したいファイル名とファイル形式を指定するだけです
scrapy crawl predict -o predict.json

これだけです。

中身を見てみましょう。

#jqを事前にインストールする必要あり
cat predict.json | jq


実行結果です。

f:id:doz13189:20170321192042p:plain


まとめ
上手くできましたか?
思いの外簡単にスクレイピング出来たと思います。
なんせ、書いたコードは30行に満たない程度ですから。

今回はファイルに保存しましたが、これをデータベースに保存してもOKですし、実際には管理のしやすさ等を考えるとそちらのほうがベターかと思います。

私もまだまだscrapyを触り始めたばかりなので、これから色々と使っていきたいと思います。

株価の予測精度が60%を超えた

【更新 2017-08-15】
未だによくアクセスがあるので、書いておきます。
この結果が検証したわけではないですが、きっと間違いです。
シミュレーション期間がとても短いこともあって、運が良かっただけのように思います。
検証するのも面倒なので、しませんが。
ただ、記事としては残しておこうと思います。
若気の至り的な自戒もこめて...

目次

予測精度が60%超えた!?

2014年8月15日〜2017年2月28日までの期間で、株価を予測するシミュレーションを行ったところ...

66.19%

となりました。


2値分類モデルで、n日後の株価が上昇しているか下落しているかを予測する、というものです。


予測対象はETFで、2013年1月時点で運用をしているという条件で絞り込んでいます。

[ 1305, 1306, 1308, 1309, 1310, 1311, 1320, 1321, 1324, 1325, 1326, 1328, 1329, 1330, 1343, 1344, 1345, 1346, 1348, 1540, 1541, 1542, 1545, 1546, 1547, 1550, 1552, 1554, 1555, 1563, 1566, 1569, 1570, 1571, 1572, 1615, 1671, 1678, 1680, 1681, 1698, 1699 ]

ETFだから予測精度が高いとかそういうことではなくて、個別銘柄でもおそらくあまり変わらない結果が出ると思います。

ETFにしているのは、購入単位が安いので売買シミュレーションがしやすいからです。

以下は平均予測精度を時系列順にプロットしたものです。

f:id:doz13189:20170303184448p:plain

これらの平均が66.19%ということになります。

定期的に大きく予測が外れるという特徴は以前から変わらずですね。

本当に予測できてるのか?

わかりません。

もう実践に投入して確かめるしかないと思ってます。


シミュレーションというシミュレーションはし尽くしました。

使用しているプログラムにも今の所ミスは見つかっていません。

ただ、今までの経験上予測精度が60%を超えると確実にミスが発見されます。

引き続きプログラムミスの可能性を疑ってかかることにします。


ということもありますが、今後はこれを活かすためにシストレやりたいなぁという方向性で頑張っています。

ただ、それらの知識が皆無なので大変です。

なんとか4月の入社までにある程度の形にもっていきたいですが、厳しいかも。

中身のアルゴリズムはあまり詳しく話しませんが...

私が株価予測を行う上で、ここを気にしたというポイントをまとめます。

2ヶ月前の自分に口酸っぱく言いたいな!という内容を書いています。

  • 株価の価格を予測しない
  • 時系列を意識する
  • 手法を組み合わせる


この3つに集約されます。

この3つを意識したあたりから、私は上手く行き出しました。

株価の価格を予測しない、というのはちょっとわかりにくいですね。

言い換えると、株価の価格を予測しても精度は上がらないよ、ということです。

じゃあ何予測すんねんって感じですね笑

これは私の経験則であり、組むアルゴリズムによってそこらへんの事情は変わると思いますが、私は価格を予測しようとしても精度は50%程度にいつも収束していきました。

だから、予測する対象を変えました。

予測する対象は、市場の方向性です。

市場の方向性とはつまり、市場が上昇傾向にあるのか、あるいは下落傾向にあるのか、です。

方向性を予測した結果を銘柄に適用しているだけです。


2つめの時系列を意識するというのは、当たり前かもしれません。

例えば、株価は自己相関しますね。(自己相関とは、上がったら下がってきて、下がったら上がってくる、という株価の性質をカッコよく言っているだけです。)

その性質を利用したアルゴリズムは数多く提唱されており、例えば、anticorなどが有名です。

anticorは時系列を強く意識したアルゴリズムと言えます。

株価の1回1回の価格形成は独立しているわけではありません。(前日の株価が次の日の株価に影響を与えている、ということ)

私は自己相関を利用しているわけではありませんが、時系列というのは強く意識しています。

株価が時間と共に変動している以上、時間という要素を抜いてはあまり上手くはいかないのじゃあないかな、というのが私の意見です。


はい、3つ目。

単発の手法ではなかなか精度は上がらないかな、というこれも私の経験則に基づいたものです。

株価に限らず、予測という分野は手法を組み合わせることで精度が劇的に上がるケースは多いと思います。

となると、ディープラーニングと何を組み合わせようかな〜、と考えてしまう人がいると思いますが、これはきっと上手く行きません。

ディープラーニングを使わないと予測できないとか、機械学習を使わないと予測できないとか、手法の問題ではないと思います。

手法を組み合わせるって言っても、考え方の問題だと私は思っています。

私は、アルゴリズムの中に強化学習を使用していますが、強化学習のどのアルゴリズムを使用しているというわけではありません。

強化学習の「報酬を最大化」する、という考え方をアルゴリズムに組み込んでいるだけです。

どうしても手法ありきで考えてしまうと、この手法は株価予測に使えるor使えないで判断してしまいます。

株価予測に最適なアルゴリズムなんてものはないので、ピッタリくるものはなかなか出会えないですよね。

色々なアルゴリズムの考え方を組み合わせながら、株価予測のアルゴリズムを構築していくのが大事かなって思います。

以上、ゆるーくポイントをまとめてみました。

ゆくゆくはアルゴリズムもフルオープンにしたいなぁと考えるもそう甘くはない

アルゴリズム取引の世界ってすごくクローズドですよね。

こんなにも様々な分野の様々な記事がネット上にアップされているにも関わらず、アルゴリズムトレードに関するものは極端に数が少なく、あったとしてもその記事の質は低かったりします。

もちろん、アルゴリズムを公開していて生き残って行ける業界ではないのですが。

ただ、ノウハウを個人個人で溜め込んで、それを墓まで持っていくスタイルなので、ノウハウの蓄積が少なく、若い人材が確実に育ちにくい形態をしています。

業界の体質上仕方がない気もしますが、なんとも歯がゆい...


今後10年でアルゴリズム取引という業界は今よりもっともっと大きくなります。

今でさえ米国では80〜90%の取引はアルゴリズムによるものであるというデータがありますし、フラッシュクラッシュなんて楽しいことも起きています。

現状、日本市場で動いているアルゴリズム取引も米国産のものが多いと言われていますし、日本のシストレ勢はまだまだ少ないように思います。

(少ないと言っても私のフォロー・フォロワーさんは優秀なシストレ勢がたくさんいますが...)


この現状をどうにかしたいなぁ、なんて考えているのでよく株価分析系の記事をできるだけわかりやすい内容にしてアップしたりはしているのですが、もっと根本の部分から変えないと現状は変わらないように感じています。

どうにかその仕組みづくりをできればなぁなんてのが最近の野望です。

最後に予測モデルで売買シミュレーションを行ったので、それを貼って記事を締めます

予測モデルと言っても、以前から使用してる予測精度が54〜55%くらいのモデルです。

(60%を超えたモデルではまだ売買シミュレーションをやっていません。)

予測モデルに従い、100万円を元手に2014年から2016年の3年間に取引を行うとどうなるかっていうシミュレーションです。

手数料はSBI証券のものを適用しています。

対象銘柄は、先ほどと同じETFであり、予測結果の中からランダムで銘柄選択をしているので、シミュレーションを20回行っています。

f:id:doz13189:20170303202833p:plain

3年間運用して、元手の100万円を割ったのは、20回中3回。

厳しい結果ですね。

予測精度と言っても、結局当たるか外れるかは確率なので、予測精度が利益に繋がるとは限りませんね。

これだとまだまだ市場投入するには早いかなって思います。

60%を超えたモデルでのシミュレーションはまだ行っていないので近々やると思います。

結果が楽しみです。(~o~)


今回は目的もなくダラダラと書いてしまって、収集がつきません。

強制的にここらで終わることにします。

終わり!

強化学習で銘柄を選んでみた(検証)

目次

今日やること

銘柄選択を強化学習に任せてみよう、ということをお題にシンプルな検証をやってみたいと思います。

強化学習

強化学習の中でも、基礎とされるn本腕バンディット問題について扱います。

相場をn本腕バンディット問題に見立てて、検証したいと思います。

そもそもn本腕バンディット問題って何?

見識高き読者は華麗に読み飛ばして下さい。

今回使用するバンディットアルゴリズムのε-グリーディ手法を私なりに説明してるだけです(数式は一切使いません)。


n本腕バンディット問題は例えで説明すると、とてもわかりやすいです。

例えスタート!!

f:id:doz13189:20170224221859j:plain

  1. ここに5つのコインがあります(画像は6枚ですが、気にしないで)
  2. 5つのコインは表がでる確率がそれぞれ異なります
  3. コインAは30%、コインBは40%、コインCは50%、コインDは60%、コインEは70%、の確率で表がでます
  4. どのコインがどの確率なのかはわかりません
  5. 5つのコインから1つだけを選んで投げる、という行動を10000回繰り返します
  6. 目的は、この10000回の中でできるだけ表を多く出したい
  7. さて、どういった戦略をとれば表を多く出せるでしょう?

10000回の試行回数の中でどれが一番表が出やすいコインを手探りで確かめなければならない、かつ、できるだけ早く見つける。

こういった状況をバンディット問題と呼びます。

(n本腕というのは選択肢の数で、今回は5つのコイン、つまり、5つの選択肢があるので5本腕バンディット問題ということになります)

そして、この手探りの効率の良さをより求めたものがバンディットアルゴリズムとして提唱されています。


さて、そろそろ戦略について考えてみましょう。


では、まずギャンブラー的戦略をとってみましょう。

ギャンブラー的戦略:5つのうちどれかを選び、それを10000回投げ続ける。コインEを偶然選ぶことができればラッキー、コインAに当たれば悲劇。


次にみんな平等、ゆとり教育的戦略をとりましょう。

ゆとり教育的戦略:みんな平等、5つとも2000回づつ投げましょう。表が出る期待値は、当然5枚のコインの期待値の平均。


次は、ちょっと頭をひねった戦略をとります。

最初の5000回は5枚とも均等にコインを投げます。

5000回投げ終わった時点で、それぞれのコインの表が出た回数を計算し、その中で一番表が出た回数が多かったものを残りの5000回投げましょう、という戦略。

実はこれはグリーディ手法と呼ばれる戦略です。

最初の5000回の中から期待値の高いものを貪欲に(Greedy)選ぶことからグリーディ手法と呼ばれています。


さて、先ほどのグリーディ手法ですが、最初に5000回は投げ過ぎじゃないですか?

もうちょっと減らしても、コインEは見つけれるんじゃないか?

1000回、いいや、100回、いやいや、20回!


20回まで減らして、もし20回の中でコインEを見つけることができれば、残りの9880回はコインEを投げれるわけです。

しかし、心配な点もあります。

それは20回の中で、たまたまコインDの表が出る回数が多くて、残りの9880回にコインDを選んでしまうケース。

悲劇ですね。

しかし、あくまでもコインの表が出るのは確率なので、十二分に考えられます。

コインEを見つけるための試行回数を減らしすぎると、こういった悲劇(不確実性)が起こりやすくなります。


ちなみにバンディット問題では。

このコインEを見つけるための行動を探索と言います。

そして、コインEの表が出る確率が高いということを見出し、コインEを投げることを知識の利用と言います。(試行回数をこなすことで得た知識を利用)


探索と知識の利用はトレードオフの関係にあり、探索をしすぎても最終的な報酬(表が出る回数)は減り、知識の利用を早い段階からしすぎても不確実性が増すことになります。

バンディットアルゴリズムでは、探索と知識の利用のバランシングの効率の良さを追求しています。

このバランスは、どこが最適かとかは扱う問題によって異なるので、最適を求めるのは難易度高めです。

今回のようなコイン投げだと、確率論的に求めることはできますが、こんな単純な問題は現実には存在しません。

この記事で扱う内容も、バランシングの最適化はまったく行っていません。(無理なので)


と、n本腕バンディット問題についてざっと説明が終わったところで、最後にもうひとつだけ戦略を上げておきます。(本命)

今回、検証で使用するものです。

ε-グリーディ手法と言って、グリーディ手法のデメリットをちょっと改善したものです。

コインEを見つけるために、最初の20回はどのコインも均等に投げるとします。

ここまではグリーディ手法と同じです。

グリーディ手法だと、残りの9880回は20回の中での表が出た回数が多かったコインをひたすら投げ続けますが、ε-グリーディ手法は、残りの9880回の中でもたまに他のコインを投げます。

もし、誤った選択をしていても、たまに他のコインを投げ、その都度表が出る期待値を計算し直すので、どこかでコインEにたどり着くことができるでしょう。

探索をある一定の確率で行い続けるのが、ε-グリーディ手法です。

ε-グリーディ手法では、このように不確実性を減らしていき、かつ最終的な報酬も求めていきます。

検証方法

相場をn本腕バンディット問題に見立てながら、検証を行っていきます。

先ほどは5つのコインでしたが、相場なので5つの銘柄です。


対象銘柄

証券コード ETF リターン
1545 (NEXT FUNDS)NASDAQ-100(R)連動型上場投信 -0.0061
1525 国際のETF VIX短期先物指数 0.035
1671 WTI原油価格連動型上場投信 0.010
1681 上場インデックスファンド海外新興国株式 0.0004
1698 上場インデックスファンド日本高配当 -0.0035

リターンは、2013年から2016年まで、10営業日保有して売却するという行動を行い、それらの平均リターンを示しています。

どの銘柄がどの平均リターンかはわからないものとします。

だいたい、リターンがバラけるように選びました。


2013年から2016年までの合計取引回数は全部で89回です。

目的は、この89回の試行回数でより平均リターン高めることです。

つまり、ε-グリーディ手法によってできるだけ少ない試行回数で、一番リターンの高い国際のETF VIX短期先物指数(1525)を見つけることができれば良いということになります。

結果

f:id:doz13189:20170224204715p:plain

平均リターンは、0.0129となりました。

国際のETF VIX短期先物指数(1525)の0.035には及ばないものの、ちゃんと1525を選べているようです。

探索と知識利用のバランスは、はじめの20回をランダムに取引し(探索)、その後は知識の利用にしています。

f:id:doz13189:20170224204933p:plain

これは試行回数ごとに選択した銘柄をプロットしています。

1525が一番多く選択されていることがわかります。

たまに他の銘柄も選択しているのがε-グリーディ手法の特徴とも言えます。


ちなみにグリーディ手法で行った際のシミュレーションも見てみましょう。

f:id:doz13189:20170225054809p:plain

平均リターンは0.020でした。

今回に限っては、ε-グリーディ手法より上を行きました。

それだけε-グリーディ手法に無駄な探索が多かったと言えます。

f:id:doz13189:20170225054835p:plain

試行回数ごとに選択した銘柄をプロットしたものを見ると、1525を選んでいることがわかります。


ここまでは、ε-グリーディ手法orグリーディ手法が上手くいったパターンでした。

次に上手く探索できず国際のETF VIX短期先物指数(1525)を見つけれなかったパターンを見てみます。

f:id:doz13189:20170224205357p:plain

平均リターンは、0.0049となりました。

国際のETF VIX短期先物指数(1525)の0.035には遠く及びません。

それもそのはず選択した銘柄を見てみると...

f:id:doz13189:20170224205512p:plain

最初はWTI原油価格連動型上場投信(1671)のリターンが高いと評価しており、途中から上場インデックスファンド海外新興国株式(1681)に乗り換えています。

残念、どっちもはずれです。


こういったこともあるので、探索と知識の利用のバランシングは慎重に行わなければいけません。

強化学習のアルゴリズムは全般的に学習までの期間にかなりの時間を要します。

試行回数89回程度ではなかなか最適な解は見つかりにくく、ある程度の不確実性は許容するしかありません。

しかし、相場の歴史は長いです。

いくらでもさかのぼって探索の期間をたっぷり取ればいいか、というとまたそうでもありません。

今回のシミュレーションの問題点

一言で言うと、相場は非定常環境であるにも関わらず、定常環境を想定したシミュレーションを行っている、ということです。

コインの表は出る確率は一定ですが(定常環境)、リターンは時間と共に平均が変化していきます(非定常環境)。

これの何がまずいかというと...

2013年から2016年の平均リターンをとったら-0.01でも、2013年から2014年というある期間をとったら+0.05かもしれない。

ということは、ε-グリーディ手法は2013年から2014年の間を探索期間として設けていると高確率で誤った知識を得ることになります。

いや、そもそも誤った知識でもありませんね。

ただ、その知識を2014年、2015年と利用していても良い結果は得ることはできません。

今回のシミュレーションで言うと、2013年〜2016年は高いリターンを示していた国際のETF VIX短期先物指数(1525)を2017年以降も買い続けていれば高いリターンを期待できるかというとそうではない、ということです、当たり前ですね笑


これを解決するには、古い知識の価値をあまり評価せず、新しい知識を評価するということが上がられます。

これを今回のシミュレーションに置き換えると、時間軸をもとにリターンを加重平均すると非定常環境に対応することができるということになります。


このように相場に合わせていくと、強化学習を使ったトレンドフォロー型のアルゴリズムができます。

(今回のシミュレーションもリターンの高いものを積極的に選ぶトレンドフォロー型)

ちなみに強化学習を使った株取引で15%の超過リターンを達成したで〜っていう論文もあります。

http://sigfin.org/?plugin=attach&refer=SIG-FIN-011-04&openfile=SIG-FIN-011-04.pdf


工夫次第で取引戦略に組み込めそうですね!!!


〜更新〜

非定常環境に対応させたバージョン

直近のリターンが高いものを高く評価した場合のシミュレーション

f:id:doz13189:20170225080339p:plain

平均リターンは0.0260となかなかの数値。

何回かシミュレーションを繰り返しましたが、比較的高い数値を出しました。


f:id:doz13189:20170225080500p:plain

試行回数ごとに選択した銘柄をプロットしたものを見ても、適度に他の銘柄を選んでいることがわかります。

以上でした。

勝機はリスク管理と分散投資にあり!?コツコツドカンはもう嫌だ!

目次

的中率は悪くないのになぜ?

最近はもっぱら機械学習での株価予測にいそしんでいます。

n日後の株価が上昇or下落を予測する2値分類モデルなのですが、ここ一ヶ月はモデルの構築よりシミュレーションに重きをおいています。

もう星の数ほどのシミュレーションをやってきたのですが、そのシミュレーションの中でたびたび理不尽なことが起こります。

それは...

株価予測の精度はそこまで悪くないのに、利益でねぇ、ってことです。

株価の予測精度は時期によってけっこうブレがあって、いい時期はだいたい55%〜60%ほどなんですが、そういった時期でも期待するほどの収益を上げることができません。

というか予測精度は55%ほどあるにも関わらず、収益のトータルがマイナスのことがあります。

これは理不尽ですね。

なぜ合理的な株式市場でこのような理不尽な出来事が起こるのでしょうか?

正体はコツコツドカン

また君か。

君はいったいどこから湧いてくるんだ。

コツコツドカンを撲滅するために

利益を上げるには、どうやら予測の精度をこれ以上あげるより、もっとやるべきことがあるようです。

それはリスク管理分散投資です。

実世界での私は元手が少ないので分散投資リスク管理もできませんが、シミュレーションの中ではお金の量は自由に増減可能です。

実世界での私は貧乏なので、自分には縁のないことだと思いこれまでリスク管理分散投資はあまり勉強してきませんでした。

というか、それって長期投資する人のためのものでしょくらいにしか思ってなかったのですが、どうやら違ったようです。


今回は、リスク管理分散投資の効果について売買シミュレーションを行い検証してみたのでその結果を記事にしました。

シミュレーションについての説明

売買戦略

機械学習で騰落を予測し、予測が上昇であれば買い、下落であれば売りのポジションを取り、10日間保有して売却します。

リスク管理の方法

現代ポートフォリオ理論に基づき、ポートフォリオに組み込む銘柄同士の相関を計算し、リスク(標準偏差)が最小になるようにポートフォリオを最適化しました。

分散投資の方法

今回は分散投資と言っても、債権、オルタナティブ、株式など金融商品の種類ごとに分けるものではありません。

あくまでも株式の中で分散させるだけで、ポートフォリオに同じ業種の銘柄ができるだけ入らないようにするというものです。

業種の判断には証券コードを使用しました。

検証方法

いくつの銘柄に分散させるか、によって分類し、それぞれで売買シミュレーションを行いました。

パターンA 1つの銘柄を購入(リスク管理なし)

パターンB 2つの銘柄を購入(リスク管理あり)

パターンC 4つの銘柄を購入(リスク管理あり)

パターンD 6つの銘柄を購入(リスク管理あり)


パターンAは銘柄が1つなので、リスク管理のしようがありませんので、リスク管理なしです。

そして、どのパターンも購入する合計の株数は1000株です。

パターンAであれば、一つの銘柄を1000株購入することになります。

パターンBであれば、500株と500株だったり、300株と700株など銘柄同士の相関係数によって比率を変えながら合計1000株購入します。

パターンC,Dまでなると、合計1000株だとキレイに分割できず、140株購入など現実にはできない買い方をしてしまっています...

プログラムの仕様を合計1000株ではなくて、合計1000万円にしていたら良かったのですが、途中で仕様を変えるのも面倒だったのでこれで押し切りました。


また、購入する銘柄は予測結果の中からランダムに選んでいます。

f:id:doz13189:20170220221907p:plain

このような形で予測結果は出力されるので、パターンAであればここから1つ銘柄を選び、パターンDであれば、ここから6つ銘柄を選びます。

検証期間

2014年から2016年までの3年間です。

取引は、2014年から20営業日ごとに2016年まで行い、合計39回の取引を行っています。

シミュレーション結果発表

パターンA 1つの銘柄を購入(リスク管理なし)

20営業日ごとに1つの銘柄を1000株買い、10日間保有して、売却するということを3年間続けた結果です。

銘柄の選定をランダムで行っているため、運要素が強いです。

そのため、同じ戦略を10回繰り返し行っています。

f:id:doz13189:20170220222432p:plain

ベストパフォーマンスが最終利益、プラス200万。

ワーストパフォーマンスの最終利益は、マイナス300万。

一回の取引で必要なのは、だいたい600万ほどです。

リスク管理なし、分散投資なしではいくら予測精度が高くてもなかなか利益に結びつきにくいわけですね...

パッと見、ランダムウォークのようですね。

10回の取引のうち6回がプラス、4回がマイナスという結果です。

パターンB 2つの銘柄を購入(リスク管理あり)

シミュレーション方法は同じです。

f:id:doz13189:20170220223319p:plain

ベストパフォーマンスが最終利益、プラス300万。

ワーストパフォーマンスの最終利益は、マイナス300万。


ベストパフォーマンスの最終利益が100万円ほどアップしました。

最終的な利益も総じて、パターンAより良さそうです。

パターンC 4つの銘柄を購入(リスク管理あり)

f:id:doz13189:20170220224029p:plain

ベストパフォーマンスが最終利益、プラス500万。

ワーストパフォーマンスの最終利益は、マイナス200万。


ベストパフォーマンスは200万ほどアップし、ワーストパフォーマンスも200万まで下がりました。

順調にリスク管理分散投資の効果が現れてきたように思います。

パターンD 6つの銘柄を購入(リスク管理あり)

f:id:doz13189:20170220224457p:plain

ベストパフォーマンスが最終利益、プラス300万。

ワーストパフォーマンスの最終利益は、マイナス100万。


ベストパフォーマンスはまたプラス300万ほどに戻ってしまいましたが、ワーストパフォーマンスは100万まで下がりました。

そして、10回のシミュレーションのうち8回がプラス、2回がマイナスになりました。

パターンDまで来ると、平均リターンもそこそこありそうです。

目算だと10回のシミュレーションの平均はプラス100万円ほどでしょう。

スタートの取引額は600万円ほどなので、3年間でプラス10%ほどの期待リターンです。

まとめ

今回のシミュレーションでは、複利、マーケットインパクト、手数料等は考慮されていません。

実践を想定するなら、もう少し洗練されたシミュレーションを行う必要があると思いますが、リスク管理分散投資の重要性という観点に注目するとなかなか興味深い結果だったと思います。


そして、このシミュレーションは10日間保有して売却するだけの戦略であり、長期投資ではありません。

ですが、リスク管理分散投資は確かに効果を発揮しました。

パターンAとパターンDを見比べれば、結果は歴然です。



今回得た知識をこれからの投資ライフに生かしていきたいです。

まだまだ素人の域を抜けれそうにないです...

最強の銘柄を決めようではないか

目次

最強の銘柄はどれだ?

粉飾決算発覚、トランプツイート砲、突如現れる空売り勢、常に起こる株式市場での混乱。

これらの横風を受けながらも直近の4年間で素晴らしい成績を残した銘柄たちをランキング形式で届けます。

対象銘柄は東証1部でかつ1日の売買高が10億円以上ある大型株に絞っています。(だいたい350銘柄ほど)

最強の定義

荒ぶる株式市場で、リスクは最小に、かつリターンを最大にしたいと投資家たちは常々考えているはず...

ここでは、リスクが最小でかつ4年間の平均リターンがプラスの銘柄を最強と定義します。

リターンとリスクの求め方

今回は、過去4年間での株価変動を対象にしています。

リターンは2013年1月4日〜2017年1月31日の間の20営業日ごとの平均変動率です。

例)

2016年12月30日時点の終値が1000円、2017年1月31日時点の終値が1100円ならば、リターンは+10%となります。

このように20営業日ごとのリターンを2013年から2017年まで計算し、それらの平均値をリターンとします。

ちなみに日経平均株価の4年間の平均リターンは0.99%です。

ということは、日経平均株価と連動するETFを買って20営業日保有すると、買った価格からだいたい+0.99%になるということです。


リスクは標準偏差です。

2013年〜2017年まで20営業日ごとのリターンを求め、それらの標準偏差がリスクとなります。

例1)

f:id:doz13189:20170217061510p:plain

2013年から2017年までのほとんどの期間が上下0.1(10%)以内に収まっていることがわかります。

実際、この銘柄の標準偏差は6.62%です。

20営業日の間、いつも上下6.62%ほど株価は変動しているということになります。

例2)

f:id:doz13189:20170217061714p:plain

激しい時はプラス0.8(80%)ほどまで上がる期間も...

かなり値動きの激しい銘柄で、この銘柄の標準偏差は22.64%です。

20営業日あると、いつも上下22.64%ほど株価は変動しているということになります。

例1と比べるとかなりリスクの大きい銘柄ということになります。


ざっとリターンとリスクについて説明したところで、最強銘柄ランキングを発表することにします。

最強の銘柄はこれだ!

順位 コード 企業名 リターン リスク
1位 2811 カゴメ 1.33% 5.05%
2位 4508 田辺三菱制約 1.23%% 5.55%
3位 2875 東洋水産 1.27% 5.56%
4位 9532 大阪ガス 0.88% 5.61%
5位 9041 近鉄グループHD 0.15% 5.80%
6位 8304 青空銀行 0.65% 5.96%
7位 7911 凸版印刷 1.33% 5.99%
8位 9020 JR東 1.19% 6.06%
9位 2897 日清食品HD 1.20% 6.11%
10位 5012 東燃ゼネラル石油 1.10% 6.12%

安定感抜群の猛者たちでした。

デンジャラスな冒険銘柄

ひたすらリターンの大きさのみに注目した銘柄です。

順位 コード 企業名 リターン リスク
1位 5801 古河電気工業 21.49% 136.36%
2位 5401 新日鉄住金 18.45% 124.64%
3位 4631 DIC 18.05% 105.07%
4位 5406 神戸製鋼所 17.93% 119.8%
5位 5711 三菱マテリアル 17.86% 116.91%
6位 8309 三井トラストHD 16.95% 107.60%
7位 4004 昭和電工 16.90% 106.82%
8位 7211 三菱自動車工業 13.39% 92.41%
9位 2201 森永製菓 13.20% 67.35%
10位 1808 長谷工コーポレーション 11.19% 57.86%

算出してみたのですが、ちょっと感覚と異なる銘柄がズラリ。

調べてみるとほとんどの銘柄が、ある期間に突出した暴騰があり平均を釣り上げているようです。

デンジャラスな冒険銘柄は上手く調べることはできませんでした...(妥協)

まとめ

いかがだったでしょうか。

簡単な計算でリターンとリスクは求めることができます。

リスクの管理をしっかりとしていきたいですね。

Pythonで機械学習を使った株価予測のコードを書こう

目次

はじめに

プログラミングを始めたばかりの人、機械学習を使って株価を分析してみたい人、このような人たちのために記事にしました。
少しでも助けとなれば私はうれしいです。

全てを読めば、株価を予測するためのコードを理解することができるよう心がけました。
理解することが大事なので、コードはシンプルにしてあります。

ひとつ注意点があります。
この記事を読むことで、株価を予測するためのコードは理解できるようになりますが、株価の予測はできません。
株価の予測は非常に難しいことであり、たくさんの工夫が必要です。
ただ、この記事は最初の一歩になると思います。
一歩さえ踏み出してしまえば、あとは各自で工夫していけるはずです。

ページの最後に本記事で使用したコードを掲載しています。

準備するもの

scikit-learn
pandas
ubuntu(OSは自由)
ネット回線

記事の流れ

  1. データ収集
  2. データの前処理
  3. モデルの学習
  4. 構築したモデルによる予測

予測手法

機械学習のランダムフォレストです。

ランダムフォレストは、調整が必要なパラメータが少なく過学習もしにくいため、機械学習の中でも扱いやすい部類に入ります。

かと言って、判別精度が悪いわけではないので非常に優秀な手法です。

ランダムフォレストについて詳しく知りたい方は以下の記事を参考にして下さい。

doz13189.hatenablog.com

データ収集

本記事で予測するのは、野村総合研究所(4307)の株価です。
以下のサイトで直近250日分のデータ(始値・高値・安値・終値出来高・売買代金)がダウンロードできます。
CSVと書かれている部分をクリックするだけです。

[4307 東証1部] 野村総合研究所 日足 時系列データ CSVダウンロード


次に説明変数となるデータを集めてきます。
野村総合研究所の株価を予測するには、野村総合研究所の株価データだけでは足りません。

では、何を集めてきたらいいでしょう?

まずは日経平均株価かな、次はTOPIX?あとドル円データも欲しいな…
あとは原油価格もあればうれしい、といろいろとあると思います。

あげだしたらきりがないし、正直それぞれ集めてくるの面倒くさいですね。
というか、こういうデータは自分で考えながら集めてくるものはありませんね。
集めれるだけデータを集めて、そこから説明変数として効果的なものを選びだすほうが効率が良いです。
少なくとも私はそうしています。

ということで、ここに載っているデータを適当に集めましょう。
ここにETF一覧が掲載されています。

stocks.finance.yahoo.co.jp

あれ?ETF??
私が探しているのは日経平均株価とか為替データで…

いいんです、ETFで。

ETFについて、とても軽く説明します。知っている方は読み飛ばして下さい。
ETFというのは、上場投資信託というもので、その名の通り投資信託が上場しているんです。
ヨーロッパ・アメリカでは有名な金融商品であり、最近は日本でも注目度が上がっている商品です。
投資信託と比べて色々とメリットはあるのですが、話が逸れそうなので詳しくは他のサイトに譲ります。

なぜ、ETFは説明変数候補として集めるかというと、指標と連動させている商品だからです。
例えば、日経225連動型上場投資信託
これは日経平均株価と連動するように運用されています。
そのため、日経平均株価を説明変数として組み込むのと、 日経225連動型上場投資信託を組み込むのは同じこと、になるんです。

ETFには様々な指標に連動させた商品があります。
上海株式、金、銀、原油、とうもろこしなどなど。
これらの指標は説明変数になりえます。

ということで、先ほどのETF一覧を見ながら、野村総合研究所の株価データをダウンロードしたサイトから集めてきましょう。

さすがに全部集めるのはしんどいので、適当に選びましょう。
ちなみに私は、

コード ETF
1309 上海株式指数・上証50連動型上場投資信託
1313 サムスンKODEX200証券上場指数投資信託
1314 上場インデックスファンドS&P日本新興株100
1322 上場インデックスファンド中国A株(パンダ)CSI300
1326 SPDRゴールド・シェア
1343 NEXT FUNDS 東証REIT指数連動型上場投信
1543 パラジウム上場信託(現物国内保管型)
1548 上場インデックスファンド中国H株(ハンセン中国企業株)
1549 上場インデックスファンドNifty50先物(インド株式)
1551 JASDAQ-TOP20上場投信
1633 NEXT FUNDS 不動産(TOPIX-17)上場投信
1673 ETFS 銀上場投資信託
1678 NEXT FUNDS インド株式指数・Nifty 50連動型上場投信
1681 上場インデックスファンド海外新興国株式(MSCIエマージング
1682 NEXT FUNDS 日経・東商取白金指数連動型上場投信
1698 上場インデックスファンド日本高配当(東証配当フォーカス100)

これらをダウンロードしました。

プラスアルファ
手動でデータを集めてくるのもいいですが、効率良く集めたいならスクレイピングがいいです。
現時点でスクレイピングがわからないという方は、「python スクレイピング]でググってみましょう。
思いの外スクレイピングが簡単にできることがわかると思います。
今回は、できるだけ記事をシンプルにしたいので余計な技術は使いません。

データが集まったらいよいよ前処理です。
前処理がおそらく一番難しくて、大変な作業です。
これさえ乗り切ってしまえばあとは楽勝です、がんばりましょう!

前処理

前処理ですること

  1. 野村総合研究所のデータと全てのETFのデータを統合して、ひとつの.csvにまとめる

まずは野村総合研究所の株価データを読み込んでみましょう。

import pandas as pd
df = pd.read_csv("code_4307.csv", header=0)
df.columns=["Date", "Open", "High", "Low", "Close", "Volume", "Trading Value"]
df["index"] = [i for i in range(len(df))]
print(df.head(10))

f:id:doz13189:20170209033100p:plain

人によっては、UnicodeDecodeErrorが出るかもしれません。
この原因は、ダウンロードしたcsvデータのcolumnsが日本語だからです。
csvデータの日付、始値、高値、安値、終値出来高の部分が文字化けしていると思うので、少し面倒ですがcsvデータからこれらを適当な英数字に修正しましょう。


さて、次のステップでETFのファイルを読み込み、それらを野村総合研究所の株価データと統合します。

そのために、まずETFのリストを作ります。
etf_listにダウンロードしたETFファイルのコードを入れましょう。

そして、ETFファイルの名前を「etf_1309.csv]にします。
ファイルの名前構成を「"etf_" + ETFコード + ".csv"」にすることで、ループ分を回した時にETFコードの部分を変えるだけで読み込むファイルを変えることができるようになります。

etf_list = [

1309,#上海株式指数・上証50連動型上場投資信託
1313,#サムスンKODEX200証券上場指数投資信託
1314,#上場インデックスファンドS&P日本新興株100
1322,#上場インデックスファンド中国A株(パンダ)CSI300
1326,#SPDRゴールド・シェア
1343,#NEXT FUNDS 東証REIT指数連動型上場投信
1543,#純パラジウム上場信託(現物国内保管型)
1548,#上場インデックスファンド中国H株(ハンセン中国企業株)
1551,#JASDAQ-TOP20上場投信
1633,#NEXT FUNDS 不動産(TOPIX-17)上場投信
1673,#ETFS 銀上場投資信託
1678,#NEXT FUNDS インド株式指数・Nifty 50連動型上場投信
1681,#上場インデックスファンド海外新興国株式(MSCIエマージング)
1682,#NEXT FUNDS 日経・東商取白金指数連動型上場投信
1698,#上場インデックスファンド日本高配当(東証配当フォーカス100)

]

さきほどの名前構成を変更したので、ループ分でetf_listに入っている全てのETFファイルを読み込むことができます。

for etf in etf_list:

	df_etf = pd.read_csv("etf_" + str(etf) + ".csv", header=0)
	df_etf.columns=["Date", "Open", "High", "Low", "Close", "Volume", "Trading Value"]


読み込むことができたら、次はETFファイルと野村総合研究所のデータを統合します。

統合する際に少し工夫が必要です。
ETFファイルは中身を見て頂ければわかると思いますが、穴ボコです。
NaNデータが多く、野村総合研究所のデータとそのまま統合すると、データの長さが異なるためズレて統合されてしまいます。

そのため、以下のコードでは野村総合研究所の日付をループ分で順番に取り出しながら、ETFファイルの日付に検索をかけます。
そして、日付が一致した日のETFのCloseデータを取り出します。
もし、そのCloseデータがNaNであった場合は前日のデータを代わりに入れています。

for etf in etf_list:

	df_etf = pd.read_csv("etf_" + str(etf) + ".csv", header=0)#データ読み込み
	df_etf.columns=["Date", "Open", "High", "Low", "Close", "Volume", "Trading Value"]#columns名を変更

	dates = []
	closeis = []
	for d in df["Date"]:
		date = df_etf.loc[(df_etf.Date == d), "Date"]#野村総合研究所の日付をETFファイルから検索
		yesterday_date = date.values[0]
		dates.append(date.values[0])#日付をデータセットに追加

		close = df_etf.loc[(df_etf.Date == d), "Close"]#日付が一致した日のETFのCloseのデータを取り出す
		if str(close.values[0]) != str("nan"):#取り出したCloseがnanでないかを判断
			yesterday_close = close.values[0]
			closeis.append(close.values[0])	

		else:
			closeis.append(yesterday_close)
		
	df_etf2 = pd.DataFrame({"Date_" + str(etf) : dates, "Close_" + str(etf) : closeis})#新しくデータフレームを作成
	df = pd.concat([df, df_etf2], axis=1)#野村総合研究所のデータとETFデータを統合

ETFデータは、Closeしか必要はありません。
しかし、プログラムでは日付データも一緒に追加しています。
これは、統合した後に目視で確認しやすいようにです。(出来上がったデータを見てもらえば、確認のしやすさがわかります)

よくデータ同士の統合で、データが一段ずれるなどのトラブルが起こります。
これはこういったトラブルを防ぐためのちょっとした工夫です。


さて、無事統合できました。
しかし、このETFデータにもうひと工夫する必要があります。

ETFのデータを階差系列に変更する必要があります。
このステップは非常に重要で、ETFの価格自体を説明変数として使っても、野村総合研究所の株価データは説明することはできません。
そのため、前日比などに変更する必要があります。

このコードをfor文の中に入れてやる必要があります。

df["diff_" + str(etf)] = (df["Close_" + str(etf)] / df["Close_" + str(etf)].shift(-1)) - 1

これで前処理は終了したので、新しくできたデータフレームをcode_4307_plus.csvとして保存します。

df.to_csv("code_4307_plus.csv")

モデルの学習

ここで新しくファイルを作成しましょう。

いよいよ機械学習で株価を予測します。

構築するモデルは、過去249日を学習して、250日目を予測するというものです。

import pandas as pd
from sklearn.ensemble import RandomForestClassifier


ETFデータを統合した野村総合研究所の株価データを表示しましょう。

df = pd.read_csv("code_4307_plus.csv")
df = df.sort_values(by=["index"], ascending=False)
print(df.tail(20))

ETFデータが全て統合されたデータが表示されたはずです。

このデータをテストデータとトレーニングデータにわけます。

df_train = df.iloc[1:len(df)-1]
#はじまりを[1:]としているのは、階差系列をとっているため[1]がNaNデータだからです。
#学習データにNaNデータがあると、エラーがでます。

df_test = df.iloc[len(df)-1:len(df)]
#テストデータには、一番最新のデータを入れます。

説明変数として使用するものをリストにしておきます。

xlist = [

"diff_1309",#上海株式指数・上証50連動型上場投資信託
"diff_1313",#サムスンKODEX200証券上場指数投資信託
"diff_1314",#上場インデックスファンドS&P日本新興株100
"diff_1322",#上場インデックスファンド中国A株(パンダ)CSI300
"diff_1326",#SPDRゴールド・シェア
"diff_1343",#NEXT FUNDS 東証REIT指数連動型上場投信
"diff_1543",#純パラジウム上場信託(現物国内保管型)
"diff_1548",#上場インデックスファンド中国H株(ハンセン中国企業株)
"diff_1551",#JASDAQ-TOP20上場投信
"diff_1633",#NEXT FUNDS 不動産(TOPIX-17)上場投信
"diff_1673",#ETFS 銀上場投資信託
"diff_1678",#NEXT FUNDS インド株式指数・Nifty 50連動型上場投信
"diff_1681",#上場インデックスファンド海外新興国株式(MSCIエマージング)
"diff_1682",#NEXT FUNDS 日経・東商取白金指数連動型上場投信
"diff_1698",#上場インデックスファンド日本高配当(東証配当フォーカス100)

]


ここで学習用のデータを作ります。
学習データの作り方は、x日のデータ(ETFの前日比)を説明変数に、x+1日の騰落を目的変数に入れます。
x+1日の株価が上昇していれば、+1を入れ、下落していれば-1を入れます。

x_train = []
y_train = []
for s in range(0, len(df_train) - 1):
	#print(df_train["Date"].iloc[s], df_train["Date"].iloc[s + 1])
	#print(df_train["Close"].iloc[s], df_train["Close"].iloc[s + 1])

	x_train.append(df_train[xlist].iloc[s])

	if df_train["Close"].iloc[s + 1] > df_train["Close"].iloc[s]:
		y_train.append(1)
	else:
		y_train.append(-1)

#print(x_train)
#print(y_train)

rf = RandomForestClassifier(n_estimators=len(x_train), random_state=0)
rf.fit(x_train, y_train)

n_estimatorsは、ランダムフォレストを構築するために生成する決定木の数です。
基本的には、データ数と同じにすれば大丈夫です。

コメントアウトしてあるprint文を表示してもらえば、一日づつズレて入っていることが解ると思います。

f:id:doz13189:20170209192840p:plain


では、最後に構築したモデルを使用して、株価を予測してみましょう。

データの中で一番最新のもの、つまり、2月7日のETFデータをtest_xとしていれます。

test_x = df_test[xlist].iloc[0]
test_y = rf.predict(test_x.reshape(1, -1))


f:id:doz13189:20170209204500p:plain

マイナス1が出たということは、2/8の株価は下落ということですね。

2月8日の株価を見てみましょう。

f:id:doz13189:20170209204350p:plain

下落しているので、予測は当たっていることになります。


以上で予測は終わりです。

もし、興味が湧いたという方がいればこのコードを少し修正して、他の日もシミュレーションをしてみると良い練習になると思います。

きっと散々な結果がでると思います。

もう一段ステップアップするには何をしたらいい?

ちょっと物足りないという人は他にも色々と試せることはあります。

  • 他の手法を試す
  • 数値を指数平滑化する
  • 過去249日で1日後を予測しているが、これが最適か考える
  • テクニカル指標など他の説明変数を試してみる

まとめ

とても簡単でしたね。

今は色々なパッケージがあるので、機械学習は簡単に扱うことができます。

案外簡単だったと思うので、この記事を機会に色々と勉強してみると面白いと思います。

今回使ったコード

ベタ打ちですみません。
ファイルは2つあります。

野村総合研究所のデータとETFデータを統合するためのファイル

import pandas as pd


df = pd.read_csv("code_4307.csv", header=0)
df.columns=["Date", "Open", "High", "Low", "Close", "Volume", "Trading Value"]
df["index"] = [i for i in range(len(df))]
print(df.head(20))

etf_list = [

		1309,#上海株式指数・上証50連動型上場投資信託

		1313,#サムスンKODEX200証券上場指数投資信託

		1314,#上場インデックスファンドS&P日本新興株100

		1322,#上場インデックスファンド中国A株(パンダ)CSI300

		1326,#SPDRゴールド・シェア

		1343,#NEXT FUNDS 東証REIT指数連動型上場投信

		1543,#純パラジウム上場信託(現物国内保管型)

		1548,#上場インデックスファンド中国H株(ハンセン中国企業株)

		#1549,#上場インデックスファンドNifty50先物(インド株式)

		1551,#JASDAQ-TOP20上場投信

		1633,#NEXT FUNDS 不動産(TOPIX-17)上場投信

		#1649,

		1673,#ETFS 銀上場投資信託

		1678,#NEXT FUNDS インド株式指数・Nifty 50連動型上場投信

		1681,#上場インデックスファンド海外新興国株式(MSCIエマージング)

		1682,#NEXT FUNDS 日経・東商取白金指数連動型上場投信

		1698,#上場インデックスファンド日本高配当(東証配当フォーカス100)

		]

for etf in etf_list:
	#print(etf)
	df_etf = pd.read_csv("etf_" + str(etf) + ".csv", header=0)
	df_etf.columns=["Date", "Open", "High", "Low", "Close", "Volume", "Trading Value"]

	dates = []
	closeis = []
	for d in df["Date"]:
		#try:
		date = df_etf.loc[(df_etf.Date == d), "Date"]
		yesterday_date = date.values[0]
		dates.append(date.values[0])

		close = df_etf.loc[(df_etf.Date == d), "Close"]
		if str(close.values[0]) != str("nan"):
			yesterday_close = close.values[0]
			closeis.append(close.values[0])	

		else:
			#print("nan")
			closeis.append(yesterday_close)
		
	df_etf2 = pd.DataFrame({"Date_" + str(etf) : dates,
							"Close_" + str(etf) : closeis})

	df = pd.concat([df, df_etf2], axis=1)
	df["diff_" + str(etf)] = (df["Close_" + str(etf)] / df["Close_" + str(etf)].shift(-1)) - 1
	#print(df)

df.to_csv("code_4307_plus.csv")


機械学習を行うためのファイル

import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

df = pd.read_csv("code_4307_plus.csv")
df = df.sort_values(by=["index"], ascending=False)
print(df.tail(20))


df = df.iloc[0:len(df) - 1]
print(df.tail())

df_train = df.iloc[1:len(df)-1]
df_test = df.iloc[len(df)-1:len(df)]

#print("train", df_train)
#print("test", df_test)

xlist = [

		"diff_1309",#上海株式指数・上証50連動型上場投資信託

		"diff_1313",#サムスンKODEX200証券上場指数投資信託

		"diff_1314",#上場インデックスファンドS&P日本新興株100

		"diff_1322",#上場インデックスファンド中国A株(パンダ)CSI300

		"diff_1326",#SPDRゴールド・シェア

		"diff_1343",#NEXT FUNDS 東証REIT指数連動型上場投信

		"diff_1543",#純パラジウム上場信託(現物国内保管型)

		"diff_1548",#上場インデックスファンド中国H株(ハンセン中国企業株)

		"diff_1551",#JASDAQ-TOP20上場投信

		"diff_1633",#NEXT FUNDS 不動産(TOPIX-17)上場投信

		"diff_1673",#ETFS 銀上場投資信託

		"diff_1678",#NEXT FUNDS インド株式指数・Nifty 50連動型上場投信

		"diff_1681",#上場インデックスファンド海外新興国株式(MSCIエマージング)

		"diff_1682",#NEXT FUNDS 日経・東商取白金指数連動型上場投信

		"diff_1698",#上場インデックスファンド日本高配当(東証配当フォーカス100)

		]


x_train = []
y_train = []
for s in range(0, len(df_train) - 1):
	print("x_train : ", df_train["Date"].iloc[s])
	print("y_train : ", df_train["Date"].iloc[s + 1])
	print("")
	x_train.append(df_train[xlist].iloc[s])

	if df_train["Close"].iloc[s + 1] > df_train["Close"].iloc[s]:
		y_train.append(1)
	else:
		y_train.append(-1)

#print(x_train)
#print(y_train)

rf = RandomForestClassifier(n_estimators=len(x_train), random_state=0)
rf.fit(x_train, y_train)


test_x = df_test[xlist].iloc[0]
test_y = rf.predict(test_x.reshape(1, -1))

print("result : ", test_y[0])