Posted at
FinTechDay 5

QuantXでロイター社提供のデータを使ったアルゴリズムを作ってみた


無料で金融アルゴリズムが作れるQuantxを使ってみた


Quantxとは

株式会社SmartTradeが提供しているアルゴリズム開発プラットフォーム

QuantX Factoryホームページ

無料でアルゴリズムを作成してバックテストするほか、アルゴリズムを販売したり、購入したりすることができる。ロイター社からデータの提供を受けており、センチメントデータを用いたアルゴリズムの作成も無料で行うことができる。

使うことのできるデータはQuantxの公式ドキュメントから

QuantXの公式ドキュメントのページ


せっかくなので、ロイター社から提供を受けているデータを使ってみる

スクリーンショット 2018-12-05 17.55.06.png

EPS, PER,PBR, ROEが使えるらしい

つい先日理論株価についてDCF法を勉強したので

理論株価を使ったアルゴリズムを作ってみたい

早速、試してみようと思いまーす‼️‼️

どうも理論株価の求め方は単純なものから複雑なものまで何種類もあるらしくDCF法が無理でも、単純なものならできそーーー

ロイターのデータを生かすことができるものを発見‼️

理論株価=現在BPS+現在EPS*PER

という求め方が存在

ただ、残念なことに、ロイター社提供のデータにはBPSがない模様

だけど、PBR=株価/BPSなので

BPS=株価/PBRで代用できる

ということで、早速、理論株価と現在株価との乖離を用いたアルゴリズムを書いてみます


qiita.py

import pandas as pd

import numpy as np

def initialize(ctx):

# 設定
ctx.configure(
target="jp.stock.daily",
channels={ # 利用チャンネル
"jp.stock": {
"symbols": [
"jp.stock.9045",
"jp.stock.7832",
"jp.stock.8028",
"jp.stock.8933",
"jp.stock.9503",
"jp.stock.9533",
"jp.stock.3360",
"jp.stock.3405",
"jp.stock.5105",
"jp.stock.4452",
"jp.stock.8113",
"jp.stock.6463",
"jp.stock.4681",
"jp.stock.9086",

],
"columns": [
"high_price_adj",
"low_price_adj",
"close_price_adj",
"eps",
"per",
"pbr",

]
}
}
)

def _TALIB_CALL(data):
hp=data["high_price_adj"].fillna(method="ffill")
lp=data["low_price_adj"].fillna(method="ffill")
cp=data["close_price_adj"].fillna(method='ffill')

eps = data["eps"].fillna(method="ffill")

per=data['per'].fillna(method='ffill')

pbr=data["pbr"].fillna(method='ffill')

bps=pd.DataFrame(data=0,columns=[],index=cp.index)
index1=pd.DataFrame(data=0,columns=[],index=cp.index)
index2=pd.DataFrame(data=0,columns=[],index=cp.index)
index3=pd.DataFrame(data=0,columns=[],index=cp.index)
index4=pd.DataFrame(data=0,columns=[],index=cp.index)
index5=pd.DataFrame(data=0,columns=[],index=cp.index)

for (sym,val) in cp.items():
bps[sym]=cp[sym]/pbr[sym]
index1[sym]=bps[sym]+(per[sym]*eps[sym])
index2[sym]=index1[sym]/cp[sym]
index3[sym]=index2[sym].rolling(window=365,center=False).max()
index4[sym]=index2[sym].rolling(window=365,center=False).min()
index5[sym]=(index2[sym]-index4[sym])/(index3[sym]-index4[sym])

buy_sig =index5[(index5>=0.9)]
sell_sig =index5[(index5<=0.18)]

buy_sig[~np.isnan(buy_sig)] = 1.0 # normalize signal
sell_sig[~np.isnan(buy_sig)] = np.nan # clear sell_sig if buy_sig is positive
sell_sig[~np.isnan(sell_sig)] = 1.0 # normalize signal

# this signal willrequire from next version.
# neutral: 0.0, positive: 1.0, negative: -1.0
market_sig = pd.DataFrame(data=0.0, columns=buy_sig.columns, index=buy_sig.index)
market_sig[buy_sig == 1.0] = 1.0
market_sig[sell_sig == 1.0] = -1.0

return {
"_eps":data["eps"].fillna(method="ffill"),
"_per":data["per"].fillna(method="ffill"),
"_pbr":data["pbr"].fillna(method="ffill"),
"buy:sig": buy_sig,
"sell:sig": sell_sig,
"index1":index1,
"index2":index2,
"index3":index3,
"index4":index4,
"index5":index5,
}

# シグナル登録
ctx.regist_signal("TALIB", _TALIB_CALL)

def handle_signals(ctx, date, current):

buy = current["buy:sig"].dropna()
#buy = buy[~buy.index.isin(done_syms)]
for (sym,val) in buy.items():
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * 1, comment="SIGNAL BUY")

ctx.logger.debug("BUY: %s, %f" % (sec.code(), val))

sell = current["sell:sig"].dropna()
#sell = sell[~sell.index.isin(done_syms)]
for (sym,val) in sell.items():
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * -1, comment="SIGNAL SELL")
ctx.logger.debug("SELL: %s, %f" % (sec.code(), val))


ざっとこんな感じですかねーーーー

銘柄はロイター社提供のデータを使う場合は、JP日経400採用銘柄しか使えないようなので、その中から良さそうなものを選びました。("jp.stock.4桁")の部分で証券番号を指定して使っています。

使用可能銘柄については、詳しくはQuantXの公式ドキュメントを見てください。

QuantXの公式ドキュメントのページ

バックテストをやってみますーーーー‼️

スクリーンショット 2018-12-05 18.32.11.png

期間は3年でバックテストしてみまーす。

スクリーンショット 2018-12-05 19.33.15.png

結果はこんな感じでーす。

3年で損益率142.89%です‼️ Maxdrowdownは-17.8%と微妙なラインですが、、、、

結構いいんではないでしょうか⁉️

ただ、もっと改善したいと思っちゃったので、、、、


改善していく

もう一つ指標を入れてみまーす。

ストキャスティクスという指標を用いてみたいと思います。

なんとこれ、わざわざ自分でコードを書かなくても、talibというライブラリを用いるとわずか数行で簡単に実装できるんです。

talibをimportして


qiita2.py

 slowk[sym],slowd[sym]=ta.STOCH(hp[sym].values.astype(np.double),

lp[sym].values.astype(np.double),
cp[sym].values.astype(np.double),
fastk_period=120,slowk_period=40,slowk_matype=0,slowd_period=3,slowd_matype=0)
fastk[sym],fastd[sym]=ta.STOCHF(hp[sym].values.astype(np.double),
lp[sym].values.astype(np.double),
cp[sym].values.astype(np.double),
fastk_period=120,fastd_period=40,fastd_matype=0)

これで簡単にストキャスティクスを計算できます。

あとは細かくシグナルを発する状況を規定して、欲しい返り値を決めておくだけです。


qiita3.py

import pandas as pd

import talib as ta
import numpy as np

def initialize(ctx):

# 設定
ctx.configure(
target="jp.stock.daily",
channels={ # 利用チャンネル
"jp.stock": {
"symbols": [
"jp.stock.9045",
"jp.stock.7832",
"jp.stock.8028",
"jp.stock.8933",
"jp.stock.9503",
"jp.stock.9533",
"jp.stock.3360",
"jp.stock.3405",
"jp.stock.5105",
"jp.stock.4452",
"jp.stock.8113",
"jp.stock.6463",
"jp.stock.4681",
"jp.stock.9086",

],
"columns": [
"high_price_adj",
"low_price_adj",
"close_price_adj",
"eps",
"per",
"pbr",

]
}
}
)

def _TALIB_CALL(data):
hp=data["high_price_adj"].fillna(method="ffill")
lp=data["low_price_adj"].fillna(method="ffill")
cp=data["close_price_adj"].fillna(method='ffill')

eps = data["eps"].fillna(method="ffill")

per=data['per'].fillna(method='ffill')

pbr=data["pbr"].fillna(method='ffill')

bps=pd.DataFrame(data=0,columns=[],index=cp.index)
index1=pd.DataFrame(data=0,columns=[],index=cp.index)
index2=pd.DataFrame(data=0,columns=[],index=cp.index)
index3=pd.DataFrame(data=0,columns=[],index=cp.index)
index4=pd.DataFrame(data=0,columns=[],index=cp.index)
index5=pd.DataFrame(data=0,columns=[],index=cp.index)
slowk=pd.DataFrame(data=0,columns=[],index=cp.index)
slowd=pd.DataFrame(data=0,columns=[],index=cp.index)
fastk=pd.DataFrame(data=0,columns=[],index=cp.index)
fastd=pd.DataFrame(data=0,columns=[],index=cp.index)
for (sym,val) in cp.items():
bps[sym]=cp[sym]/pbr[sym]
index1[sym]=bps[sym]+(per[sym]*eps[sym])
index2[sym]=index1[sym]/cp[sym]
index3[sym]=index2[sym].rolling(window=365,center=False).max()
index4[sym]=index2[sym].rolling(window=365,center=False).min()
index5[sym]=(index2[sym]-index4[sym])/(index3[sym]-index4[sym])
slowk[sym],slowd[sym]=ta.STOCH(hp[sym].values.astype(np.double),
lp[sym].values.astype(np.double),
cp[sym].values.astype(np.double),
fastk_period=120,slowk_period=40,slowk_matype=0,slowd_period=3,slowd_matype=0)
fastk[sym],fastd[sym]=ta.STOCHF(hp[sym].values.astype(np.double),
lp[sym].values.astype(np.double),
cp[sym].values.astype(np.double),
fastk_period=120,fastd_period=40,fastd_matype=0)

buy_sig =index5[(index5>=0.9)&(fastd<=24)]
sell_sig =index5[(index5<=0.18)&(fastd>=85)]

buy_sig[~np.isnan(buy_sig)] = 1.0 # normalize signal
sell_sig[~np.isnan(buy_sig)] = np.nan # clear sell_sig if buy_sig is positive
sell_sig[~np.isnan(sell_sig)] = 1.0 # normalize signal

# this signal willrequire from next version.
# neutral: 0.0, positive: 1.0, negative: -1.0
market_sig = pd.DataFrame(data=0.0, columns=buy_sig.columns, index=buy_sig.index)
market_sig[buy_sig == 1.0] = 1.0
market_sig[sell_sig == 1.0] = -1.0

return {
"_eps":data["eps"].fillna(method="ffill"),
"_per":data["per"].fillna(method="ffill"),
"_pbr":data["pbr"].fillna(method="ffill"),
"buy:sig": buy_sig,
"sell:sig": sell_sig,
"index1":index1,
"index2":index2,
"index3":index3,
"index4":index4,
"index5":index5,
"slowk":slowk,
"slowd":slowd,
"fastk":fastk,
"fastd":fastd
}

# シグナル登録
ctx.regist_signal("TALIB", _TALIB_CALL)

def handle_signals(ctx, date, current):
buy = current["buy:sig"].dropna()
#buy = buy[~buy.index.isin(done_syms)]
for (sym,val) in buy.items():
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * 1, comment="SIGNAL BUY")

ctx.logger.debug("BUY: %s, %f" % (sec.code(), val))

sell = current["sell:sig"].dropna()
#sell = sell[~sell.index.isin(done_syms)]
for (sym,val) in sell.items():
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * -1, comment="SIGNAL SELL")
ctx.logger.debug("SELL: %s, %f" % (sec.code(), val))


これが最終版ですね。バックテストをしてみます。

スクリーンショット 2018-12-05 19.47.49.png

損益率が193.61%に改善しました‼️ MaxDrowdown-13.9%に改善しました‼️‼️

採用銘柄とか、使う指標、シグナルを発する状況をいじると、どんどん成績を改善できそうですねーー


最後に

皆さんも、ぜひQuantXでアルゴリズム作って試してみてください‼️‼️‼️‼️

無料で作れますよーーーー‼️‼️

QuantX Factoryホームページ