Smart Tradeとは
Smart Tradeとは株式会社Smart Tradeが提供する、株式投資アルゴリズムの開発プラットフォームサービスの名称
現在はβ版だが、近々正式版がリリースされるとの事
(2017/11/25追記:2017/11/20に正式版リリース完了、サービス名称も「QuantX」に)
Pythonを用いてトレーディングアルゴリズムを記述することができ、バックテストも簡便に行うことができる機能を備えている
下記HPからサービスを利用する事が可能
https://smarttrade.co.jp
実装したアルゴリズムの元ネタ
書籍名:投資苑 心理・戦略・資金管理
著者:アレキサンダー・エルダー
訳者:福井強
2000年8月 初版第1刷発行
第8章 新しいテクニカル指標 エルダー線 の頁より
アルゴリズムの説明
利用するテクニカル指標
エルダー線に基づくトレーディングルールは下記の3つの指標を利用
1.直近13日間の指数移動平均線(EMA)
2.ブル・パワー(=日足のチャートの高値-13日EMA)
3.ベア・パワー(=日足のチャートの安値-13日EMA)
トレーディングルール
買いのルール
1.トレンドが上向きである(当日の株価がEMAより上にある)
2.ベア・パワーが負の数値であるものの、上昇している
3.ブル・パワーの直近の天井が前回の天井を上回っている
(4.ベア・パワーが価格との強気の乖離を形成して上昇しつつある)
*本文中には望ましいが必須ではないとの事なので今回は割愛
売りのルール
1.トレンドが下向きである(当日の株価がEMAより下にある)
2.ブル・パワーが正の数値であるものの、下落している
3.ベア・パワーの直近の底が前回の底を下回っている
(4.ブル・パワーが価格との弱気の乖離を形成して下落しつつある)
*本文中には望ましいが必須ではないとの事なので今回は割愛
実装したコード
13日間の指数移動平均線
# buy signal
# 終値を設定
cp = data["close_price_adj"].fillna(method='ffill')
pd_cp = pd.DataFrame(data=cp,columns=cp.columns, index=cp.index)
# 売買条件判定用
result1 = pd.DataFrame(data=cp,columns=cp.columns, index=cp.index)
result2 = pd.DataFrame(data=cp,columns=cp.columns, index=cp.index)
# EMAの計算
EMA13 = {}
for (sym,val) in cp.items():
EMA13[sym] = ta.EMA(cp[sym].values.astype(np.double),timeperiod=13)
pd_EMA13 = pd.DataFrame(data=EMA13,columns=cp.columns, index=cp.index)
# EMAの売買条件判定のための指標を設定
EMA_ratio = cp / pd_EMA13
ブル・パワー
# bull power
hp = data["high_price_adj"].fillna(method='ffill')
bull_power = hp - pd_EMA13
pd_bull_power = pd.DataFrame(data=bull_power)
# 直近25日間でのブル・パワーの最大値
pd_bull_power_max = pd.DataFrame(data=bull_power).rolling(25).max()
pd_bull_power_shift = pd_bull_power.shift(periods=2)
# ブル・パワーの差分(負なら2日前より下落している)
delta_bull = pd_bull_power - pd_bull_power_shift
ベア・パワー
# bear_power < 0 & delta > 0
lp = data["low_price_adj"].fillna(method='ffill')
bear_power = lp - pd_EMA13
pd_bear_power = pd.DataFrame(data=bear_power)
# 直近25日間でのベア・パワーの最小値
pd_bear_power_min = pd.DataFrame(data=bear_power).rolling(25).min()
pd_bear_power_shift = pd_bear_power.shift(periods=2)
# ベア・パワーの差分(正なら2日前より上昇している)
delta_bear = pd_bear_power - pd_bear_power_shift
売買条件の設定
buy_sig = result1[(EMA_ratio>1) & (bear_power < 0) & (delta_bear > 0) & (pd_bull_power == pd_bull_power_max)]
sell_sig = result2[(EMA_ratio<1) & (bull_power > 0) & (delta_bull < 0) & (pd_bear_power == pd_bear_power_min)]
コード全体
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.7203", "jp.stock.7267",
"jp.stock.7270", "jp.stock.7269",
"jp.stock.7259", "jp.stock.7202",
"jp.stock.7203", "jp.stock.7205",
"jp.stock.7208", "jp.stock.7211"
],
"columns": [
#"open_price_adj",
"high_price_adj",
"low_price_adj",
#"close_price1",
"close_price_adj",
#"volume_adj",
#"txn_volume",
]
}
}
)
def _elder_ray_signal(data):
#buy signal
cp = data["close_price_adj"].fillna(method='ffill')
pd_cp = pd.DataFrame(data=cp,columns=cp.columns, index=cp.index)
result1 = pd.DataFrame(data=cp,columns=cp.columns, index=cp.index)
result2 = pd.DataFrame(data=cp,columns=cp.columns, index=cp.index)
EMA13 = {}
for (sym,val) in cp.items():
EMA13[sym] = ta.EMA(cp[sym].values.astype(np.double),timeperiod=13)
pd_EMA13 = pd.DataFrame(data=EMA13,columns=cp.columns, index=cp.index)
#EMA condition
EMA_ratio = cp / pd_EMA13
#bear power
#bear_power < 0 & delta > 0
lp = data["low_price_adj"].fillna(method='ffill')
bear_power = lp - pd_EMA13
pd_bear_power = pd.DataFrame(data=bear_power)
pd_bear_power_min = pd.DataFrame(data=bear_power).rolling(25).min()
pd_bear_power_shift = pd_bear_power.shift(periods=2)
delta_bear = pd_bear_power - pd_bear_power_shift
#sell signal
#bull power
hp = data["high_price_adj"].fillna(method='ffill')
bull_power = hp - pd_EMA13
pd_bull_power = pd.DataFrame(data=bull_power)
pd_bull_power_max = pd.DataFrame(data=bull_power).rolling(25).max()
pd_bull_power_shift = pd_bull_power.shift(periods=2)
delta_bull = pd_bull_power - pd_bull_power_shift
buy_sig = result1[(EMA_ratio>1) & (bear_power < 0) & (delta_bear > 0) & (pd_bull_power == pd_bull_power_max)]
sell_sig = result2[(EMA_ratio<1) & (bull_power > 0) & (delta_bull < 0) & (pd_bear_power == pd_bear_power_min)]
return {
"EMA13_price": pd_EMA13,
"bear_power": bear_power,
"delta_bear": delta_bear,
"bull_power": bull_power,
"bull_power_max": pd_bull_power_max,
"delta_bull": delta_bull,
"cp":cp,
"buy:sig": buy_sig,
"sell:sig": sell_sig,
"buy:sig2": (EMA_ratio>1) & (bear_power < 0) & (delta_bear > 0) & (pd_bull_power == pd_bull_power_max),
"sell:sig2": (EMA_ratio<1) & (bull_power > 0) & (delta_bull < 0) & (pd_bear_power == pd_bear_power_min)
}
ctx.regist_signal("elder_ray_signal", _elder_ray_signal)
def handle_signals(ctx, date, current):
buy = current["buy:sig"].dropna()
for (sym, val) in buy.items():
sec = ctx.getSecurity(sym)
sec.order(sec.unit()*5, comment="シグナル買(%f)" % val)
pass
sell = current["sell:sig"].dropna()
for (sym, val) in sell.items():
sec = ctx.getSecurity(sym)
sec.order_target_percent(0, comment="シグナル売(%f)" % val)
pass
pass
バックテスト結果
実行したアルゴリズムに関してバックテストの結果を下記にて記載
バックテスト条件
バックテストの条件は
資金:1000万円
バックテスト期間:2015/7/1-2017/3/31の21カ月間を設定
売買に用いた銘柄
バックテストにはデフォルトでサービスに入っていた自動車関連銘柄のセットを使用
バックテスト結果サマリー
バックテストの結果、ベンチマークである日経225をアウトパフォームして、期間の損益率9.36%を達成
個別銘柄の売買の様子
個別銘柄の売買の様子
アイシン精機は良いタイミングで売買出来ているように見える
(赤丸:買いのポイント、青丸:売りのポイント、縦線は発生した売買シグナル)
売買シグナルが発生したのに売買が行われていない箇所は、ポジションが一杯もしくは0だったと思われる
トヨタ自動車は負けている
ホンダも同じく負けている
単純にロングした場合との比較
ロングのみのコード
def long_only(data):
data = data["close_price_adj"].fillna(method='ffill')
buy_sig = data[(data>-10)]
sell_sig = data[(data<0)]
return {
"data": data,
"buy:sig": buy_sig,
"sell:sig": sell_sig,
}
# シグナル登録
ctx.regist_signal("long_only", long_only)
def handle_signals(ctx, date, current):
buy = current["buy:sig"].dropna()
for (sym, val) in buy.items():
sec = ctx.getSecurity(sym)
sec.order(500000/val, comment="シグナル買(%f)" % val)
pass
sell = current["sell:sig"].dropna()
for (sym, val) in sell.items():
sec = ctx.getSecurity(sym)
sec.order_target_percent(0, comment="シグナル売(%f)" % val)
pass
pass
単純にロングした場合というのは下記のような状況
パフォーマンスは日経225と同じような推移
今後の取り組み
優良なアルゴリズムの実装と開発