Posted at
FinTechDay 14

QuantXで一目均衡表を作ってみた(Python) ・続編


QuantXとは

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

QuantX Factoryの公式ホームページ

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

詳しくはQuantXの公式ドキュメントのページ


前回までにやったこと


一目均衡表を考えた

基準線=(26日最高値+26日最安値)÷2

転換線=(9日最高値+9日最安値)÷2

先行スパン1本目=基準線と転換線の平均を26日先行したもの

先行スパン2本目=52日間の最高値と最安値の平均を26日先行したもの

遅行線=当日の終値を26日先行させたもの

という感じです。


基準線と転換線のクロスを用いた

詳しくはQuantXで一目均衡表を作ってみた(Python)をみてください‼️

前回作ったアルゴリズムがこれでーーーーす。


qiita1.py

import numpy as np

import pandas as pd
import talib as ta

def initialize(ctx):
# 設定
ctx.logger.debug("initialize() called")
ctx.configure(
channels={ # 利用チャンネル
"jp.stock": {
"symbols": [
"jp.stock.1333",#マルハニチロ(水産)
"jp.stock.1605",#国際石開帝石(鉱業)
"jp.stock.1925",#ハウス(建設)
"jp.stock.2914",#JT(食品)
"jp.stock.3402",#東レ (繊維)
"jp.stock.3861",#王子HD(パルプ・紙)
"jp.stock.4519",#中外薬(医薬品)
"jp.stock.4452",#花王(化学)
"jp.stock.5020",#JXTG(石油)
"jp.stock.5108",#ブリヂストン(ゴム)
"jp.stock.5201",#AGC(窯業)
"jp.stock.5401",#新日鉄住金(鉄鋼)
"jp.stock.5802",#住友電(非鉄金属製品)
"jp.stock.6367",#ダイキン(機械)
"jp.stock.6758",#ソニー(電気機器)
"jp.stock.7012",#川重(造船)
"jp.stock.7203",#トヨタ(自動車)
"jp.stock.4543",#テルモ(精密機器)
"jp.stock.7951",#ヤマハ(その他製造)
"jp.stock.8058",#三菱商(商社)
"jp.stock.9983",#ファストリ(小売業)
"jp.stock.8306",#三菱UFJ(銀行)
"jp.stock.8604",#野村(証券)
"jp.stock.8766",#東京海上(保険)
"jp.stock.8253",#クレゾン(その他金融)
"jp.stock.8801",#三井不動産(不動産)
"jp.stock.9022",#JR東海(鉄道)
"jp.stock.9062",#日通(陸運)
"jp.stock.9104",#商船三井(海運)
"jp.stock.9202",#ANAHD(空運)
"jp.stock.9301",#三菱倉(倉庫)
"jp.stock.9437",#NTTドコモ(通信)
"jp.stock.9503",#関西電(電力)
"jp.stock.9531",#東ガス(ガス)
"jp.stock.6178",#日本郵政(サービス)
],
"columns": [
#"open_price_adj", # 始値(株式分割調整後)
"high_price_adj", # 高値(株式分割調整後)
"low_price_adj", # 安値(株式分割調整後)
#"volume_adj", # 出来高
#"txn_volume", # 売買代金
"close_price", # 終値
"close_price_adj", # 終値(株式分割調整後)
]
}
}
)

def _my_signal(data):
cp=data["close_price_adj"].fillna(method="ffill")
hp=data["high_price_adj"].fillna(method="ffill")
result1=pd.DataFrame(data=0,columns=[],index=cp.index)
sample1=pd.DataFrame(data=0,columns=[],index=cp.index)
result1=pd.DataFrame(data=0,columns=[],index=cp.index)
sample3=pd.DataFrame(data=0,columns=[],index=cp.index)
index3=pd.DataFrame(data=0,columns=[],index=cp.index)
index6=pd.DataFrame(data=0,columns=[],index=cp.index)
index7=pd.DataFrame(data=0,columns=[],index=cp.index)
index8=pd.DataFrame(data=0,columns=[],index=cp.index)
index12=pd.DataFrame(data=0,columns=[],index=cp.index)
index13=pd.DataFrame(data=0,columns=[],index=cp.index)
index14=pd.DataFrame(data=0,columns=[],index=cp.index)
index1=data["high_price_adj"].fillna(method='ffill').rolling(window=9,center=False).max()
index2=data["low_price_adj"].fillna(method="ffill").rolling(window=9,center=False).min()
index3=(index1+index2)/2 #転換線
index4=data["high_price_adj"].fillna(method='ffill').rolling(window=26,center=False).max()
index5=data["low_price_adj"].fillna(method='ffill').rolling(window=26,center=False).min()
index6=(index4+index5)/2 #基準線
index7=(index3+index6)/2
index8=index7.shift(26) #先行スパン1
index9=data["high_price_adj"].fillna(method='ffill').rolling(window=52,center=False).max()
index10=data["low_price_adj"].fillna(method='ffill').rolling(window=52,center=False).min()
index11=(index8+index9)/2
index12=index11.shift(26) #先行スパン2
index13=index3-index6
index14=index13.shift(1)
index15=data["close_price_adj"].fillna(method='ffill').shift(26)

buy_sig=index13[(index13>0)&(index14<0)]
sell_sig=index13[(index13<0)&(index14>0)]
return {
"buy:sig":buy_sig,
"sell:sig":sell_sig,
"転換線:g2":index3,
"基準線:g2":index6,
"先行スパン1:g2":index8,
"先行スパン2:g2":index12,
"遅行線:g2":index15
}

# シグナル登録
ctx.regist_signal("my_signal", _my_signal)

def handle_signals(ctx, date, current):
'''
current: pd.DataFrame
'''

buy = current["buy:sig"].dropna()
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))
pass

sell = current["sell:sig"].dropna()
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))
pass



今回やること

先行スパン1本目先行スパン2本目の間のを用いたアルゴリズムを作成する‼️‼️


まず雲の解釈について

終値が雲の下から雲上に到達し、クロスした点をBUY

終値が雲の上から雲上に到達し、クロスした点をSELL

とします。


雲とのクロスを解釈するアルゴリズムがこちらです

まず、データの格納倉庫を増やしておきます.こちらのコードでできます。


qiita2.py

      index15=pd.DataFrame(data=0,columns=[],index=cp.index)

index16=pd.DataFrame(data=0,columns=[],index=cp.index)
index17=pd.DataFrame(data=0,columns=[],index=cp.index)
index18=pd.DataFrame(data=0,columns=[],index=cp.index)
index19=pd.DataFrame(data=0,columns=[],index=cp.index)
index20=pd.DataFrame(data=0,columns=[],index=cp.index)
index21=pd.DataFrame(data=0,columns=[],index=cp.index)

次に、終値と雲とのクロスを計測するコードを加えます。


qiita3.py

      index16=np.maximum(index8,index12)

index17=np.minimum(index8,index12)
index18=cp-index17
index19=index18.shift()
index20=cp-index16
index21=index20.shift()


そして、最後に、売買シグナルの規定に条件を加えます。


qiita4.py

     buy_sig=index18[(index18>0)&(index19<0)&(index13>0)&(index14<0)]

sell_sig=index20[(index20<0)&(index21>0)&(index13<0)&(index14>0)]

これで完成です‼️‼️

完成版のアルゴリズムがこちらです


qiita5.py

import numpy as np

import pandas as pd
import talib as ta

def initialize(ctx):
# 設定
ctx.logger.debug("initialize() called")
ctx.configure(
channels={ # 利用チャンネル
"jp.stock": {
"symbols": [
"jp.stock.1333",#マルハニチロ(水産)
"jp.stock.1605",#国際石開帝石(鉱業)
"jp.stock.1925",#ハウス(建設)
"jp.stock.2914",#JT(食品)
"jp.stock.3402",#東レ (繊維)
"jp.stock.3861",#王子HD(パルプ・紙)
"jp.stock.4519",#中外薬(医薬品)
"jp.stock.4452",#花王(化学)
"jp.stock.5020",#JXTG(石油)
"jp.stock.5108",#ブリヂストン(ゴム)
"jp.stock.5201",#AGC(窯業)
"jp.stock.5401",#新日鉄住金(鉄鋼)
"jp.stock.5802",#住友電(非鉄金属製品)
"jp.stock.6367",#ダイキン(機械)
"jp.stock.6758",#ソニー(電気機器)
"jp.stock.7012",#川重(造船)
"jp.stock.7203",#トヨタ(自動車)
"jp.stock.4543",#テルモ(精密機器)
"jp.stock.7951",#ヤマハ(その他製造)
"jp.stock.8058",#三菱商(商社)
"jp.stock.9983",#ファストリ(小売業)
"jp.stock.8306",#三菱UFJ(銀行)
"jp.stock.8604",#野村(証券)
"jp.stock.8766",#東京海上(保険)
"jp.stock.8253",#クレゾン(その他金融)
"jp.stock.8801",#三井不動産(不動産)
"jp.stock.9022",#JR東海(鉄道)
"jp.stock.9062",#日通(陸運)
"jp.stock.9104",#商船三井(海運)
"jp.stock.9202",#ANAHD(空運)
"jp.stock.9301",#三菱倉(倉庫)
"jp.stock.9437",#NTTドコモ(通信)
"jp.stock.9503",#関西電(電力)
"jp.stock.9531",#東ガス(ガス)
"jp.stock.6178",#日本郵政(サービス)
],
"columns": [
#"open_price_adj", # 始値(株式分割調整後)
"high_price_adj", # 高値(株式分割調整後)
"low_price_adj", # 安値(株式分割調整後)
#"volume_adj", # 出来高
#"txn_volume", # 売買代金
"close_price", # 終値
"close_price_adj", # 終値(株式分割調整後)
]
}
}
)

def _my_signal(data):
cp=data["close_price_adj"].fillna(method="ffill")
hp=data["high_price_adj"].fillna(method="ffill")
result1=pd.DataFrame(data=0,columns=[],index=cp.index)
sample1=pd.DataFrame(data=0,columns=[],index=cp.index)
result1=pd.DataFrame(data=0,columns=[],index=cp.index)
sample3=pd.DataFrame(data=0,columns=[],index=cp.index)
index3=pd.DataFrame(data=0,columns=[],index=cp.index)
index6=pd.DataFrame(data=0,columns=[],index=cp.index)
index7=pd.DataFrame(data=0,columns=[],index=cp.index)
index8=pd.DataFrame(data=0,columns=[],index=cp.index)
index12=pd.DataFrame(data=0,columns=[],index=cp.index)
index13=pd.DataFrame(data=0,columns=[],index=cp.index)
index14=pd.DataFrame(data=0,columns=[],index=cp.index)
index15=pd.DataFrame(data=0,columns=[],index=cp.index)
index16=pd.DataFrame(data=0,columns=[],index=cp.index)
index17=pd.DataFrame(data=0,columns=[],index=cp.index)
index18=pd.DataFrame(data=0,columns=[],index=cp.index)
index19=pd.DataFrame(data=0,columns=[],index=cp.index)
index20=pd.DataFrame(data=0,columns=[],index=cp.index)
index21=pd.DataFrame(data=0,columns=[],index=cp.index)
index1=data["high_price_adj"].fillna(method='ffill').rolling(window=9,center=False).max()
index2=data["low_price_adj"].fillna(method="ffill").rolling(window=9,center=False).min()
index3=(index1+index2)/2 #転換線
index4=data["high_price_adj"].fillna(method='ffill').rolling(window=26,center=False).max()
index5=data["low_price_adj"].fillna(method='ffill').rolling(window=26,center=False).min()
index6=(index4+index5)/2 #基準線
index7=(index3+index6)/2
index8=index7.shift(26) #先行スパン1
index9=data["high_price_adj"].fillna(method='ffill').rolling(window=52,center=False).max()
index10=data["low_price_adj"].fillna(method='ffill').rolling(window=52,center=False).min()
index11=(index8+index9)/2
index12=index11.shift(26) #先行スパン2
index13=index3-index6
index14=index13.shift()
index15=data["close_price_adj"].fillna(method='ffill').shift(26)
index16=np.maximum(index8,index12)
index17=np.minimum(index8,index12)
index18=cp-index17
index19=index18.shift()
index20=cp-index16
index21=index20.shift()

buy_sig=index18[(index18>0)&(index19<0)&(index13>0)&(index14<0)]
sell_sig=index20[(index20<0)&(index21>0)&(index13<0)&(index14>0)]

return {
"buy:sig":buy_sig,
"sell:sig":sell_sig,
"転換線:g2":index3,
"基準線:g2":index6,
"先行スパン1:g2":index8,
"先行スパン2:g2":index12,
"遅行線:g2":index15,
"先行スパン(大)":index16,
"先行スパン(小)":index17
}

# シグナル登録
ctx.regist_signal("my_signal", _my_signal)

def handle_signals(ctx, date, current):
'''
current: pd.DataFrame
'''

buy = current["buy:sig"].dropna()
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))
pass

sell = current["sell:sig"].dropna()
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))
pass



気になる結果は?

スクリーンショット 2018-12-14 18.43.44.png

前回、基準線と転換線のクロスだけを用いた時は、3年11%の利益だったのが、雲のクロスを条件に加えることで34%にまで改善しました‼️‼️

シグナルはこんな感じです。

スクリーンショット 2018-12-14 19.00.44.png

基準線と転換線のクロス雲のクロス同時に起こるところで売買シグナルを発したので、雲の効果が分かりにくくなっているので、、、、

雲だけでバックテストをしたものをお見せします


qiita6.py

buy_sig=index18[(index18>0)&(index19<0)]

sell_sig=index20[(index20<0)&(index21>0)]

とすれば雲だけを条件にできます。

スクリーンショット 2018-12-14 18.50.47.png

なかなかいい売買シグナルが出ています‼️‼️‼️

チャートを見る限り、上手く使えば、雲は高い効果を発揮できそうです。

株式銘柄をいじってみると、結果が上がる予感がします:smile:

バックテスト結果が上がり次第、記事を書くので、続編をお待ちください:pray:

ご購読ありがとうございました:yum::yum::yum::yum: