今回は、テクニカル指標 MACDを検証してみたいと思います。
・投資予算に制限を加える
・共通コードを関数化して可読性を向上させる その2
・共通コードを関数化して可読性を向上させる その3
・本ブログの内容において、正当性を保証するものではありません。
・本ブログを利用して損失を被った場合でも一切の責任を負いません。
・最終的な決定は、ご自身の判断(自己責任)でお願い致します。
MACDを活用した売買ポイントの検証
こちらのページでも紹介されている通り、MACD売買ポイントは一般に以下とされます。
◆買い:先行するMACDが、遅行する同平均(SIGNAL)を上抜く
◆売り:先行するMACDが、遅行する同平均(SIGNAL)を下抜く
これをProtraで、以下のように記述しました。
◆買い:以下を満たしたとき、翌日の始値が買う
・MACD(5-20) > signal(9)となったとき
◆売り:以下のいずれかを満たしたとき、翌日の始値で売る
・MACD(5-20) < signal(9)となったとき
●予算無制限、対象銘柄:売上上位500銘柄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
#loop-type: date-only #================================================== # MACD.pt #-------------------------------------------------- # このシステムのルール # <買い条件> # ・MACD(5-20) > signal(9)となったとき # を満たしたとき、翌日の始値で買う # # <売り条件> #・MACD(5-20) < signal(9)となったとき #・購入から9999日経過(便宜上) # を満たしたとき、翌日の始値で売る #-------------------------------------------------- # written by グコウ, 2018/8/30 #================================================== require "TIlib" require "Utility" require "TrendCheck" codes = CodeList if $code_num && $code_num != Length(codes) Print("前回と異なる銘柄リストでは実行できません。") Dummy end $code_num = Length(codes) #グローバル変数を初期化 if ! $__INIT__ $budgetIni = 10000000 $budget = $budgetIni #投資総額 (1000万円) $buyUnit = 1000000 #1回の購入資金 (100万円) $MaxHoldDay = 9999 #最大保有日数 $Interest = 0 #無制限(0) / 単利(1) / 複利(2) #------------------------------------------------ $set = [$code_num] $buy = [$code_num] $hold = [$code_num] #------------------------------------------------ $MACD = [$code_num] #------------------------------------------------ $__INIT__ = 1 end def Main(i) #================================================== # 条件(買条件, 売条件共通部分) #================================================== if Index == null return end if ! $MACD[i] #Tilibのオブジェクト生成 $MACD[i] = MACD_new(5, 20, 9) #銘柄ごとのグローバル変数を初期化 $hold[i]=0 return end #前日のMACDを保管 ymacdV = MACD_value($MACD[i]) ymacdS = MACD_signal($MACD[i]) #指標の計算を1日進める MACD_next($MACD[i]) macdV = MACD_value($MACD[i]) macdS = MACD_signal($MACD[i]) #------------------------------------------------- #計算 #------------------------------------------------- #指標の計算に必要な日数を経過していない場合は何もしない if !macdV ||!macdS || !ymacdV || !ymacdS return end #================================================== # 条件1 #================================================== if 1==PricedataExistCheck(Close) return end #エントリーの条件を判定 if (! $hold[i] && macdV > macdS && ymacdV < ymacdS) #================================================== # 売買(買い) #================================================== $long = 0 $long = Num($buyUnit,Close) Buying(i) #================================================== # 条件2 #================================================== elsif $hold[i] if 1==PricedataExistCheck(Close) return end if $set[i] < 1 $set[i] = $set[i] + 1 return end $set[i] = $set[i] + 1 if ($set[i] > $MaxHoldDay || macdV < macdS) #================================================== # 売買(売り) #================================================== Selling(i) end end end #==================== # 銘柄コードを変えながらMain関数を実行 #==================== i = -1 while i + 1 < $code_num i = i + 1 {codes[i]}Main(i) end |
結果はこちら。
取引回数が尋常じゃないほど多いですね。MACDの買いシグナルはしょっちゅう生じているためです。またリーマンショックの影響を顕著に受けています。このままでは、とてもじゃないですが使用できません。
続いて こちらで示されている、ダイバージェンス現象をコードに取り入れてみます。そのままの条件を入れると コードが複雑になるため、少し改変して以下のようにしました。
◆買い:以下を満たしたとき、翌日の始値が買う
・MACD(5-20) > signal(9)となったとき かつ
・上記のとき直近の同条件時より、MACDの値が大きい場合 かつ
・上記のとき直近の同条件時より、終値が小さい場合
◆売り:以下のいずれかを満たしたとき、翌日の始値で売る
・MACD(5-20) < signal(9)となったとき
●予算無制限、対象銘柄:売上上位500銘柄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
#loop-type: date-only #================================================== # MACD2.pt #-------------------------------------------------- # written by グコウ, 2018/8/30 #================================================== require "TIlib" require "Utility" require "TrendCheck" codes = CodeList if $code_num && $code_num != Length(codes) Print("前回と異なる銘柄リストでは実行できません。") Dummy end $code_num = Length(codes) #グローバル変数を初期化 if ! $__INIT__ $budgetIni = 10000000 $budget = $budgetIni #投資総額 (1000万円) $buyUnit = 1000000 #1回の購入資金 (100万円) $MaxHoldDay = 9999 #最大保有日数 $Interest = 0 #無制限(0) / 単利(1) / 複利(2) #------------------------------------------------ $set = [$code_num] $buy = [$code_num] $hold = [$code_num] #------------------------------------------------ $MACD = [$code_num] $buyflag = [$code_num] $recordflag = [$code_num] $dayflag = [$code_num] #------------------------------------------------ $__INIT__ = 1 end def Main(i) #================================================== # 条件(買条件, 売条件共通部分) #================================================== if Index == null return end if ! $MACD[i] #Tilibのオブジェクト生成 $MACD[i] = MACD_new(5, 20, 9) #銘柄ごとのグローバル変数を初期化 $hold[i]=0 $buyflag[i]=0 $dayflag[i]=0 return end #前日のMACDを保管 ymacdV = MACD_value($MACD[i]) ymacdS = MACD_signal($MACD[i]) #指標の計算を1日進める MACD_next($MACD[i]) macdV = MACD_value($MACD[i]) macdS = MACD_signal($MACD[i]) #------------------------------------------------- #計算 #------------------------------------------------- #指標の計算に必要な日数を経過していない場合は何もしない if !macdV ||!macdS || !ymacdV || !ymacdS return end #(追加)--------------------------------------------- stpflg1 = 0 #ダイバージェンス現象の記述 if macdV > macdS && ymacdV < ymacdS if $buyflag[i]==1 && $recordflag[i] < macdV && {-$dayflag[i]}Close > Close $buyflag[i]=0 $recordflag[i] = 0 stpflg1 = 1 elsif $buyflag[i]==1 $recordflg[i] = macdV $dayflag[i] = 0 stpflg1 = 0 elsif $buyflag[i]==0 $buyflag[i]=1 $recordflag[i] = macdV $dayflag[i] = 0 stpflg1 = 0 end $dayflag[i] = $dayflag[i] + 1 #================================================== # 条件1 #================================================== if 1==PricedataExistCheck(Close) return end #エントリーの条件を判定 if (! $hold[i] && stpflag = 1) #================================================== # 売買(買い) #================================================== $long = 0 $long = Num($buyUnit,Close) Buying(i) #================================================== # 条件2 #================================================== elsif $hold[i] if 1==PricedataExistCheck(Close) return end if $set[i] < 1 $set[i] = $set[i] + 1 return end $set[i] = $set[i] + 1 if ($set[i] > $MaxHoldDay || macdV < macdS) #================================================== # 売買(売り) #================================================== Selling(i) end end end #==================== # 銘柄コードを変えながらMain関数を実行 #==================== i = -1 while i + 1 < $code_num i = i + 1 {codes[i]}Main(i) end |
スパゲッティコード化してきました…。
74-95行目の追加部分は、以下のような処理がされています。
- MACDがSignalを 初めて上抜きしたとき、
$buyflag[i]
に1が入る。
$recordflag[i]には、この日のMACDの値を入れています。
また2.以降、この日の終値を参照するため、$dayflagに0を入れています。 - ifを抜けたところで、$dayflagに+1しています。
- $buyflag[i]が1で、MACDがSignalを上抜きしたときに、1回目の上抜き日と比較し、MACDの値が大きい かつ 終値が小さい 場合にstpflag1に1を入れます(買い条件)。
$buyflag[i]は0に戻します。 - $buyflag[i]が1で、MACDがSignalを上抜きしたときでも、3.の条件を満たさない場合は、この日を基準点とするため、$recordflag[i]と$dayflag[i]をリセットします。
結果がこちら。多少改善したものの、あまり傾向は変わらないようです。
買いシグナル:1回目と2回目の期間に制限を加えたり、両日の終値の変化率にしきい値を設けるような調整はできそうです。
また勝ちトレードの平均期間が20日以上に対し、負けトレードは約10日となっています。この辺りに改善のヒントがありそうです。
おまけ
売条件,トレンド条件を調整すると、わりと右肩上がりの利益が得られます。(オーバーフィッティングに注意)