#今回のアルゴリズム
小型成長株メインで、移動平均線MA25とMA5を利用した順張りアルゴリズムを作成し実装してみました。
#移動平均線とは
移動平均線は、一定期間の平均価格を日々計算して算出した値を、単純平均したものです。
例えば5日移動平均値は5日分の平均価格となります。そして、日々の平均価格を線でつないだものが5日移動平均線となります。
平均価格(ここでは終値の平均)を使用することで日中の大きな変動に惑わされることなく、現在の相場の方向性(トレンド)がどちらを向いているのか(上がっているのか、下がっているのか)を見ることができます。
####よく利用される移動平均線の種類
・短期線 … 5日、10日
・中期線 … 20日、25日、75日
・長期線 … 100日、200日
#アルゴリズム
###銘柄
東証1部・2部・マザーズに上場している売上高成長率30%以上の銘柄をスクリーニングしました。
また、小型成長株がメインのポートフォリオなため、どうしてもダウントレンドの際にパフォーマンスが安定しないと考え、緩和するためにダブルインバースを組み込みました。
###シグナル
買い:MA25 +2%
売り:MA5 -2%
損切:なし
利確:なし
##コード
import pandas as pd
import talib as ta
import numpy as np
def initialize(ctx):
# 設定
ctx.logger.debug("initialize() called")
ctx.configure(
target="jp.stock.daily",
channels={ # 利用チャンネル
"jp.stock": {
"symbols": [
'jp.stock.1360', # ダブルインバース
'jp.stock.4571', # ナノキャリア
'jp.stock.4586', # メドレックス
'jp.stock.4597', # ソレイジア
'jp.stock.4598', # DELTA-P
'jp.stock.6027', # 弁護士コム
'jp.stock.6030', # アドベンチャ
'jp.stock.6033', # エクストリーム
'jp.stock.6034', # MRT
'jp.stock.6086', # シンメンテHD
'jp.stock.6090', # HMT
'jp.stock.6095', # メドピア
'jp.stock.6172', # メタップス
'jp.stock.6190', # PXB
'jp.stock.6192', # HyAS&Co.
'jp.stock.6195', # ホープ
'jp.stock.6232', # ACSL
'jp.stock.6537', # WASHハウス
'jp.stock.6553', # ソウルドアウト
'jp.stock.6561', # HANATOUR
'jp.stock.6572', # RPA
'jp.stock.6577', # ベストワン
'jp.stock.7033', # MSOL
'jp.stock.7034', # プロレド
'jp.stock.7035', # anfac
'jp.stock.7046', # TDSE
'jp.stock.7047', # ポート
'jp.stock.7172', # JIA
'jp.stock.8789', # フィンテック
'jp.stock.9271', # 和 心
],
"columns": [
#"open_price_adj", # 始値(株式分割調整後)
#"high_price_adj", # 高値(株式分割調整後)
#"low_price_adj", # 安値(株式分割調整後)
"close_price", # 終値
"close_price_adj", # 終値(株式分割調整後)
"volume_adj", # 出来高
"txn_volume", # 売買代金
]
}
}
)
def _mavg_signal(data):
#ns_sentiment = data["ns_sentiment"].fillna(method="ffill")
# ctx.logger.debug(ns_sentiment)
m25 = data["close_price_adj"].fillna(method='ffill').ewm(span=25).mean()
dfma25 = (data["close_price_adj"] - m25) / m25 * 100
m5 = data["close_price_adj"].fillna(method='ffill').ewm(span=5).mean()
dfma5 = (data["close_price_adj"] - m5) / m5 * 100
buy_sig = dfma25[(dfma25 > 2.0)]
sell_sig = dfma5[(dfma5 < -2.0)]
return {
"mavg_25:price": m25,
"mavg_5:price": m5,
#"mavg_ratio:ratio": ratio,
"buy:sig": buy_sig,
"sell:sig": sell_sig,
}
# シグナル登録
ctx.regist_signal("mavg_signal", _mavg_signal)
def handle_signals(ctx, date, current):
'''
current: pd.DataFrame
'''
done_syms = set([])
for (sym,val) in ctx.portfolio.positions.items():
returns = val["returns"]
ctx.logger.debug("%s %f" % (sym, 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 = current["buy:sig"].dropna()
for (sym,val) in buy.items():
if sym in done_syms:
continue
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():
if sym in done_syms:
continue
sec = ctx.getSecurity(sym)
sec.order(sec.unit() * -1, comment="SIGNAL SELL")
#ctx.logger.debug("SELL: %s, %f" % (sec.code(), val))
pass
昨年の暴落期間を含めても+18.9%とまずまずの成果ではないでしょうか。
#まとめ
色々な期間でバックテストを試みたものの、やはりダウントレンドになると、パフォーマンスがいまいちでしたので、下落相場であってもハイパフォーマンスを発揮できるよう、他のシグナルを追加するなど、引き続き改善を図っていきたいと思います。