移動平均+RSI
先日,RSIのアルゴリズムをQuantXで書いてみましたが,今回はRSIに移動平均を組み合わせたアルゴリズムを書いてみます.
ストラテジーの基本方針は,
1. 複数の移動平均を使う
2. 移動平均をみて,上昇トレンドであるかどうか確認
3. 全移動平均よりも今日のロウソク足の位置が上にあることを確認
4. 短期移動平均>中期移動平均>長期移動平均という位置関係にあるか確認
5. 上記の条件が揃っている間はロングポジションを保持
6. ただし,RSIが90に入るような事があれば,ポジション解消
7. もしくは,RSIが60を切った場合は,ポジション解消
ここで,「移動平均をみて,上昇トレンドであるかどうか確認」をどのように表現するか考えてみます.図は日経平均株価の2017年10月頃のチャートに,5日25日75日の移動平均をプロットした図です.
上記図より,上昇トレンドとは,3つの移動平均線が前日よりも高い位置にあること,と定義することにします.よってここでは,移動平均の前日比が3日連続ポジティブであるという事を上昇トレンドであるという判断に使いたいと思います.
シグナル
上記1から5の条件が揃っている間は買い持ち.
手仕舞い
上記6,7が発生した時
コード
import numpy as np
import talib as ta
def initialize(ctx):
# 設定
ctx.ma_shortterm = 5
ctx.ma_midterm = 25
ctx.ma_longterm = 75
ctx.target = 0.10
ctx.period = 5
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": ["open_price_adj", # 始値(株式分割調整後)
"close_price_adj", # 終値(株式分割調整後)
]}})
def _MYSIGNAL(data):
df_open = data["open_price_adj"].fillna(method='ffill')
df_close = data["close_price_adj"].fillna(method='ffill')
# 移動平均
df_sma_short = df_close.rolling(window=ctx.ma_shortterm).mean()
df_sma_middle = df_close.rolling(window=ctx.ma_midterm).mean()
df_sma_long = df_close.rolling(window=ctx.ma_longterm).mean()
# 移動平均の前日比が3日連続ポジティブであるかどうか
# memo 参照
df_sma_short_uptrend = df_sma_short.pct_change().rolling(window=3,).min() > 0
df_sma_middle_uptrend = df_sma_middle.pct_change().rolling(window=3,).min() > 0
df_sma_long_uptrend = df_sma_long.pct_change().rolling(window=3,).min() > 0
df_uptrend = df_sma_short_uptrend & df_sma_middle_uptrend & df_sma_long_uptrend
# 全移動平均よりも今日のロウソク足の位置が上にあることを確認
# つまり,始値も終値も移動平均線より上に位置していることを確認
df_upper_than_ma = (df_open > df_sma_short) & (df_open > df_sma_middle) & (df_open > df_sma_long) & (df_close > df_sma_short) & (df_close > df_sma_middle) & (df_close > df_sma_long)
# 短期移動平均>中期移動平均>長期移動平均という位置関係にあるか確認
df_ma_posion = (df_sma_short > df_sma_middle) & (df_sma_middle > df_sma_long)
# RSI>90 もしくは RSI<60 であればポジションクローズ
df_rsi = df_close.apply(lambda s: ta.RSI(s.values.astype(np.double), timeperiod=ctx.period),axis=0)
df_position_close_condition = (df_rsi > 90) | (df_rsi < 60)
# 買いシグナル
buy_sig = df_uptrend & df_upper_than_ma & df_ma_posion
sell_sig = df_position_close_condition
return {
"buy:sig": buy_sig,
"sell:sig": sell_sig,
}
# シグナル登録
ctx.regist_signal("MYSIGNAL", _MYSIGNAL)
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
移動平均の前日比が3日連続ポジティブであるかどうか
これを確認するために,過去三日間の前日比で1番小さい値がポジティブであるという確認を行いました.
df_sma_short.pct_change().rolling(window=3,).min() > 0
感想
- 今まで書いたアルゴリズムの中で今のところ一番いいですね.
- 銘柄は前回の記事で使った銘柄をそのまま使っているだけなので,このあたりは工夫の余地はあると思います.
- その他,移動平均の期間,RSIの閾値など,色々試してみる価値はありそうですね.
- RSIといえば, @kozzy さんのQuantX 上で RSI による売買アルゴリズムを開発する が分かりやすいのでオススメです.ぜひご一読下さい.
- 甲子園始まりましたね.自分の出身地と関係ない高校同士の試合の時は,公立高校もしくは地方の学校を応援するタイプです.
免責注意事項
- このコードに基づき投資した結果、損害が発生しても,一切責任を持ちません.
- このコードが正しく機能する保証は一切致しません. このアルゴリズムを勧めているわけではありません.あくまで QuantX / Python のサンプルコードとして掲載しているだけです.