ストキャスティクス
今日は個人投資家の間でも非常に人気があるらしいストキャスティクス(stochastics)をQuantXで書いてみたいと思います.
ストキャスティクスの計算式は非常に簡単で,基本となるファストストキャスティクスは以下の計算式でラインを引き,シグナルを探します.
%K = \frac{直近の終値-過去n日間の最安値}{過去n日間の最高値-過去n日間の最安値} \times 100 \\
%D = m日の%Kの単純移動平均
%K
が%D
を上抜いたら買い,逆に%K
が%D
を割り込んだら売りというシグナルになるのが一般的ですが,この %K
と%D
を使うシグナルは短期売買向きで,長期保有をしたい投資家は,%D
をさらに単純移動平均したSD
(Slow D)と%D
自身の動きを見るスローストキャスティクスというシグナルを使うそうです.
今回も,TA-LibにStochastic関数があり,
親切にも,ファストストキャスティクスSTOCHF
とスローストキャスティクス関数STOCH
が用意されていますので,それを利用したいと思います.
シグナル
ファストストキャスティクス
%K
が%D
を上抜いたら買い,逆に%K
が%D
を割り込んだら売り
スローストキャスティクス
%D
がSD
を上抜いたら買い,逆に%D
がSD
を割り込んだら売り
ただし,SD
が20%〜80%の間にあるときは,シグナルが出ても無視する.(ダマシ減らしの工夫だそうです)
参照:オシレーター分析/ストキャスティクス | はじめてのテクニカル分析 / マネックス証券
手仕舞い
シグナルに書いた売りのタイミングで手仕舞う.
コード
import talib as ta
import pandas as pd
import numpy as np
def initialize(ctx):
# 設定
ctx.fastK_period = 20
ctx.fastD_period = 3
ctx.slowK_period = 3
ctx.slowD_period = 3
ctx.upper_thred = 80
ctx.lower_thred = 20
ctx.target = 0.10
ctx.codes = [1605, 1925, 2503, 4519, 4911, 6301, 6752, 7741, 8001 ]
ctx.symbol_list = ["jp.stock.{}".format(code) for code in ctx.codes]
ctx.configure(
channels={ # 利用チャンネル
"jp.stock": {
"symbols": ctx.symbol_list,
"columns": [
"high_price_adj", # 高値(株式分割調整後)
"low_price_adj", # 安値(株式分割調整後)
"close_price_adj", # 終値(株式分割調整後)
]}})
def _STOCHASTIC_FAST(data):
df_high = data["high_price_adj"].fillna(method='ffill')
df_low = data["low_price_adj"].fillna(method='ffill')
df_close = data["close_price_adj"].fillna(method='ffill')
d_fastK = dict()
d_fastD = dict()
for symbol in data.minor_axis:
fastK, fastD = ta.STOCHF(df_high[symbol].values.astype(np.double),
df_low[symbol].values.astype(np.double),
df_close[symbol].values.astype(np.double),
fastk_period=ctx.fastK_period,
fastd_period=ctx.fastD_period,)
d_fastK[symbol] = fastK
d_fastD[symbol] = fastD
df_fastK = pd.DataFrame(d_fastK, index=data.major_axis)
df_fastD = pd.DataFrame(d_fastD, index=data.major_axis)
buy_sig = (df_fastK > df_fastD) & (df_fastK.shift(1) < df_fastD.shift(1))
sell_sig = (df_fastK < df_fastD) & (df_fastK.shift(1) > df_fastD.shift(1))
return {
"fastK":df_fastK,
"fastD": df_fastD,
"buy:sig":buy_sig,
"sell:sig":sell_sig,
}
def _STOCHASTIC(data):
df_high = data["high_price_adj"].fillna(method='ffill')
df_low = data["low_price_adj"].fillna(method='ffill')
df_close = data["close_price_adj"].fillna(method='ffill')
d_slowK = dict()
d_slowD = dict()
for symbol in data.minor_axis:
slowK, slowD = ta.STOCH(df_high[symbol].values.astype(np.double),
df_low[symbol].values.astype(np.double),
df_close[symbol].values.astype(np.double),
fastk_period=ctx.fastK_period,
slowk_period=ctx.slowK_period,
slowd_period=ctx.slowD_period)
d_slowK[symbol] = slowK
d_slowD[symbol] = slowD
df_slowK = pd.DataFrame(d_slowK, index=data.major_axis)
df_slowD = pd.DataFrame(d_slowD, index=data.major_axis)
buy_sig = (df_slowK > df_slowD) & (df_slowK.shift(1) < df_slowD.shift(1)) & (df_slowD < ctx.lower_thred)
sell_sig = (df_slowK < df_slowD) & (df_slowK.shift(1) > df_slowD.shift(1)) & (df_slowD > ctx.upper_thred)
return {
"slowK": df_slowK,
"slowD": df_slowD,
"buy:sig":buy_sig,
"sell:sig":sell_sig,
}
# シグナル登録 memo 参照
ctx.regist_signal("STOCHASTIC_FAST", _STOCHASTIC_FAST)
#ctx.regist_signal("STOCHASTIC", _STOCHASTIC)
def handle_signals(ctx, date, current):
df = current.copy()
# 買いシグナル
df_long = df[df["buy:sig"]]
if not df_long.empty:
for (sym, val) in df_long.iterrows():
sec = ctx.getSecurity(sym)
msg = "買いシグナル"
sec.order_target_percent(ctx.target, comment= msg)
# 売り(ポジションクローズ)シグナル
df_sell = df[df["sell:sig"]]
if not df_sell.empty:
for (sym, val) in df_sell.iterrows():
sec = ctx.getSecurity(sym)
msg = "売りシグナル"
sec.order_target_percent(0, comment= msg)
結果
ファストストキャスティクス
スローストキャスティクス
memo
シグナル登録
今回はファスト用とスロー用のシグナルを作って,regist_signal
関数に一つ渡す(一つはコメントアウト)という形を取りました.一つずつお試しください.
感想
- 夏休み子ども科学電話相談は毎年聞いています.恐竜キッズには全くついていけません.
- もし電話して質問できるなら,ゴジラが火を吹く仕組みを教えてもらいたいです.
- 今回の銘柄選びは,セクターが重ならないように選びました.
- スローとファストを比べて,たしかに,スローの方が成績が良いことは確認出来ました.これは研究しがいがありそうですね.
- 「
SD
が20%〜80%の間にあるときは,シグナルが出ても無視」は非常に重要なようです.これを外すとかなり成績が悪くなります.
免責注意事項
- このコードに基づき投資した結果、損害が発生しても,一切責任を持ちません.
- このコードが正しく機能する保証は一切致しません.
- このアルゴリズムを勧めているわけではありません.あくまで QuantX / Python のサンプルコードとして掲載しているだけです.