#はじめに
Quantx Factoryでは、株売買アルゴリズムが作ることができ、その中で、talibというライブラリーを使うと、ローソク足を用いたアルゴリズムを簡単に作ることが出来ます。
そこで、今回は、トレンド指標(ローソク足のThree Outside Up/Down)とオシレータ指標(RSI)を組み合わせたアルゴリズムを作っていきたいと思います。
#オシレータ、トレンド指標とは?
株取引をするする上で、参考になるものの一つにテクニカル指標というものがあります。
このテクニカル指標は「トレンド系」「オシレーター系」などに分類することができます。
一般的に、トレンド系は、全体的な流れを読むことができて、オシレーター系は、相場の過熱感(買われ過ぎ・売られ過ぎ)を見ることができる指標だといわれています。
また、トレンド系では、順張り系であり、今のトレンドに乗って利益を出す方法を見つけ出す分析方法といわれています。
一方、オシレーター系は逆張り系であり、買われすぎ、売られすぎを追い、その逆に動いて利益を出す方法を見つける分析方法といわれています。
ローソク足はトレンド系であり、RSIはオシレーター系の代表になります。
これらの指標一つ一つにはそれぞれ長所と短所があるのでうまく組み合わせながら使用していきます。
詳しい説明は、参考文献をお読みください。( https://www.daiwa.jp/seminar/technical/09/ )( https://www.gaitame.com/beginner/qa_lesson2.html )
#コードサンプル例
# 必要なライブラリーをimportする
import maron
import maron.signalfunc as sf
import maron.execfunc as ef
import pandas as pd
import talib as ta
import numpy as np
# オーダ方法を決定する
ot = maron.OrderType.MARKET_OPEN # シグナルがでた翌日の始値のタイミングでオーダー
# 銘柄、columnsの取得を行う
# 初期化を行う
def initialize(ctx):
ctx.configure(
channels={ # 利用チャンネル
"jp.stock": {
"symbols": [
"jp.stock.2914", #JT(日本たばこ産業)
"jp.stock.8766", #東京海上ホールディングス
"jp.stock.8031", #三井物産
"jp.stock.8316", #三井住友フィナンシャルグループ
"jp.stock.8411", #みずほフィナンシャルグループ
"jp.stock.9437", #NTTドコモ
"jp.stock.4502", #武田薬品工業
"jp.stock.8058", #三菱商事
"jp.stock.9433", #KDDI
"jp.stock.9432", #日本電信電話
"jp.stock.7267", #ホンダ(本田技研工業)
"jp.stock.8306", #三菱UFJフィナンシャル・グループ
"jp.stock.4503", #アステラス製薬
"jp.stock.4063", #信越化学工業
"jp.stock.7974", #任天堂
"jp.stock.6981", #村田製作所
"jp.stock.3382", #セブン&アイ・ホールディングス
"jp.stock.9020", #東日本旅客鉄道
"jp.stock.8802", #三菱地所
"jp.stock.9022", #東海旅客鉄道
"jp.stock.9984", #ソフトバンクグループ
"jp.stock.6861", #キーエンス
"jp.stock.6501", #日立製作所
"jp.stock.6752", #パナソニック
"jp.stock.6758", #ソニー
"jp.stock.6954", #ファナック
"jp.stock.7203", #トヨタ自動車
"jp.stock.7751", #キヤノン
"jp.stock.4452", #花王
"jp.stock.6098", #リクルートホールディングス
],
"columns": [
"open_price_adj", # 始値(株式分割調整後)
"high_price_adj", # 高値(株式分割調整後)
"low_price_adj", # 安値(株式分割調整後)
"close_price", # 終値
"close_price_adj", # 終値(株式分割調整後)
#"volume_adj", # 出来高
#"txn_volume", # 売買代金
]
}
}
)
# シグナル定義
def _my_signal(data):
# 終値等の取得を行い、欠損値補完を行う。
cp = data["close_price_adj"].fillna(method='ffill')
op = data["open_price_adj"].fillna(method= 'ffill')
hp = data["high_price_adj"].fillna(method="ffill")
lp = data["low_price_adj"].fillna(method="ffill")
#RSI指標に関して
rsi = pd.DataFrame(data=0,columns=[], index=cp.index)
for (sym,val) in cp.items():
rsi[sym] = ta.RSI(cp[sym].values.astype(np.double), timeperiod=14)
rsi_buy = rsi[(rsi < 30)]
rsi_sell = rsi[(rsi > 70)]
rsi_buy[(rsi < 30)] = True
rsi_sell[(rsi > 70)] = False
# ローソク足についてを計算
candle_1 = pd.DataFrame(data=0,columns=[], index=cp.index)
for(sym,val) in cp.items():
candle_1[sym] = ta.CDL3OUTSIDE(op[sym],hp[sym],lp[sym],cp[sym])
# true,falseのbool型にする
candle_1_buy = candle_1[(candle_1 == -100)]
candle_1_sell = candle_1[(candle_1 == 100)]
candle_1_buy[(candle_1 == -100)] = True
candle_1_sell[(candle_1 == 100)] = False
# 売買シグナルを定義(bool値で返す)
buy_sig = candle_1_buy & rsi_buy
sell_sig = candle_1_sell & rsi_sell
# market_sigという全て0が格納されているデータフレームを作成
market_sig = pd.DataFrame(data=0.0, columns=cp.columns, index=cp.index)
# buy_sigがTrueのとき1.0、sell_sigがTrueのとき-1.0とおく
market_sig[buy_sig == True] = 1.0
market_sig[sell_sig == True] = -1.0
market_sig[(buy_sig == True) & (sell_sig == True)] = 0.0
return {
"rsi:rsi":rsi,
"market:sig": market_sig,
"candle:1":candle_1
}
# シグナル登録
ctx.regist_signal("my_signal", _my_signal)
def handle_signals(ctx, date, current):
'''
current: pd.DataFrame
'''
market_sig = current["market:sig"]
done_syms = set([])
# 損切り、利確の設定
for (sym, val) in ctx.portfolio.positions.items():
returns = val["returns"]
if returns < -0.03:
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="損切り(%f)" % returns)
done_syms.add(sym)
elif returns > 0.05:
sec = ctx.getSecurity(sym)
sec.order(-val["amount"], comment="利益確定売(%f)" % returns)
done_syms.add(sym)
# 買シグナルについて注文方法を設定する
buy = market_sig[market_sig > 0.0]
for (sym, val) in buy.items():
if sym in done_syms:
continue
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * 1, orderType=ot, comment="SIGNAL BUY")
#ctx.logger.debug("BUY: %s, %f" % (sec.code(), val))
pass
# 売シグナルも同様に行う
sell = market_sig[market_sig < 0.0]
for (sym, val) in sell.items():
if sym in done_syms:
continue
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * -1,orderType=ot, comment="SIGNAL SELL")
#ctx.logger.debug("SELL: %s, %f" % (sec.code(), val))
pass
#解説
candle_1 = pd.DataFrame(data=0,columns=[], index=cp.index)
for(sym,val) in cp.items():
candle_1[sym] = ta.CDL3OUTSIDE(op[sym],hp[sym],lp[sym],cp[sym])
上記のコードのta.CDL3OUTSIDE
に自分の使いたいtalibのコードを入れる。
このtalibのシグナルは-100,0,100のみで出てくる。
シグナルが100の時に売りシグナルが出てくるとは限らないので両方試してみて自分で結果を見て判断する。
今回は-100がでたときなるに売りシグナルであったので、下記のようなコードを書いた。
# true,falseのbool型にする
candle_1_buy = candle_1[(candle_1 == -100)]
candle_1_sell = candle_1[(candle_1 == 100)]
candle_1_buy[(candle_1 == -100)] = True
candle_1_sell[(candle_1 == 100)] = False
また、rsi、ローソク足共に、だましのシグナルを出す可能性があるため、組み合わせることでだましを回避してより精度の高いシグナルを出せるようにする。
buy_sig = candle_1_buy & rsi_buy
sell_sig = candle_1_sell & rsi_sell
上記のように買いシグナルと売りシグナルを定義することで、rsiとローソク足のシグナルが両方でているときに売買できるようになる。
前回よりもローソク足の活用方法が見えてきた気がしますが、組み合わせると大幅にシグナル回数が減ってしまうことや損益率のみを比べるとあまりメリットを感じることが出来ない結果になってしまいました。
やはり、ローソク足の中でも何を使うのか、何とどのように組み合わせるのかによっても大きく変わってくることが分かったので、次回はそこら辺を研究していきたいと思います。