バックテスト興味が薄れてきた。
毎年同じ事を言ってるよね。
この時期には薄れるのは、仕事を淡々と進めるだけで窮地に追いやられて無いからだと思ってる。
年末年始は事業計画書作成したり、成果検証したり、委託費用の見積書を作成したり……結構大変だからね。
試験勉強してたら部屋の掃除をしたくなる
と同じじゃない?
この症状には学術的に名称がついている。
セルフハンディキャッピング
失敗した時の言い訳を用意しておこうという心理作用。
心理学では「先延ばし行動」と呼ばれる。
これ、本当かな?
言い訳を用意したところで
叱られる
だけじゃん。
無意識な症状というから定かじゃ無いけどさ。
『掃除をしていたから勉強できなかった』ということならば、勉強しない言い訳になって、自分を守ることになる
学習院大学文学部心理学科の伊藤忠弘教授
これ本当かなぁ……?
上司「なんで事業計画が出来てないの?」
私「株のバックテストしてました。キリッ」
上司「馬ww」
理由になる訳がない。
単に現実逃避したくなるだけじゃない?
テスト期間中は掃除以外にも、
旅行やテニスラケットのガットの張替え……
など普段やらない事が気になってたわ。
それに「掃除」で済むなら一時間だけでもすれば良いと思うよ。
もしくはテスト期間前に掃除を終わらせば良いんじゃない?症状が分かってるのだし。
興味が薄れている中、バックテスト検証に関してコメントを貰った。
こんにちは、いつも検証記事見させてもらってます。
バックテストのネタ不足との事で「恐怖で買って、強欲で売る」短期売買法 という本にRSIパワーゾーン戦略というものがあるのですが、宜しかったら検証して頂けないでしょうか?本を読んだだけでは最大ドローダウンもわからない状況です。
…(後略)
あら、稀有な方がおりました。
コメント有効化にすると荒れると思ってずっとしてなかったけど、受け取ると嬉しいものだねーー。
まぁ、皆さん「バックテスト」しか興味無いっぽいけどね。
私の日記って
皆の知らない疑問・噂をネホリハホリ調べる
がテーマなんだよね。今更だけど。
なので扱うネタが多岐に渡ってる。
おかげでネタも尽きずに20年以上続いてるわ。
まぁ昔は単なるエッセイの記事も多いけど……。
バックテストも疑問に対する調査の一つなので やってみよーーー!
ローレンス・A・コナーズ(Laurence A. Connors)氏って誰?
資産運用会社のLCAキャピタルとマーケット調査会社であるコナーズ・リサーチのCEO(最高経営責任者)。
1995年以降に投資情報の提供会社のコナーズ・グループを含め、売上高数百万ドル規模の投資関連企業2社を築いた。
また、コナーズ・グループは2009年にアントレックス非上場企業指数から10大急成長私企業の1社に二度選ばれた。
著書は次のとおり。
- 『魔術師リンダ・ラリーの短期売買入門』(リンダ・ブラッドフォード・ラシュキとの共著)
- 『コナーズの短期売買実践』
- 『コナーズの短期売買入門』
- 『コナーズの短期売買戦略』
- 『高勝率システムの考え方と作り方と検証』
- 『コナーズRSI入門』
- 『アルファフォーミュラ』(クリス・ケインとの共著)
……。
うん、知らなかった。
RSIパワーゾーン短期売買法の期待値検証
コナーズによると、1993年~2017年の期間のSPYをRSIパワーゾーンを30に設定して検証した場合、90.59%の勝率(平均利益率1.73%)となったと説明している。
より具体的に内容を知りたい場合は、次の本が参考になる。
が、コメントと同じくストラテジーの部分を抜粋して載せているサイトまで紹介してくれた。みきまる氏のサイトだね。
- 1. SPY(S&P500ETF)はその200日単純移動平均線を上回っている。これによって、より長期の上昇トレンド途上にあると特定できる。
- 2. SPYの4期間RSIは30を下回って引ける。また、25を下回っているとき(これは相場がさらに売られ過ぎになったことを意味する)ときに買い増しした場合の検証結果を示す。大引けにSPYを買う。
- 3. ポジションを取っているときに、4期間RSIが25を下回って引けたら、2回目に同じ口数を買う。これは要するに、通常はより安値でポジションを2倍にするということだ。
- 4. 4期間RSIが55を上回って引けたときに売る。
うん、よく分からない。
(C)大場つぐみ、小畑健/DEATH NOTE
結局、色々な他のサイトを見ながら内容を理解した。ストラテジーは次のとおり。
【基本設定】
- 全銘柄対象
【仕掛けのルール】
- 前日終値が200日単純移動平均線を上回っている(上昇トレンドの特定)
- RSI(4日)が30を下回っている
- その日の終値(大引け)で買う
【増し玉(ナンピン)のルール】
- 価格が下落し4期間RSIが25(20)を下回って引けたらポジションを2倍にする。
【手仕舞いのルール】
- RSI(4日)が55を上回ったタイミングで売る。
簡単に言えば、移動平均線でトレンドを確認し、上昇トレンド時に価格の下落によって市場に恐怖が高まるRSIの水準で買えば高勝率を得られると言うこと。
更にナンピンでリスクを限定する。
ただ、所感は手仕舞いの日数を設定しなくとも短期取引になるのか心配だ。
実装するための問題点
意味がわかると凄く簡単そうだ。でも多少の問題がある。
ナンピン
をサポートしてなかった……。
そんな需要あるなんて思ってなかったーーー。
ライブラリを修正することで実現は簡単にできた。
今後「株数の指定手仕舞い」……のようなストラテジがある場合には実現できないけどね。
また、
ナンピンで同じ銘柄数を購入する
仕組みも必要だ。
今までは「1銘柄に対して購入上限額を指定」しか実現してなかったからね。
まぁ、これも今のフレームワークで実現可能だった。
色々なストラテジー対応してきたけど、まだまだ学ぶ事は多いなーーー。
実行するための問題点
もう一つ、実際にトレードする時の問題点がある。
「大引けで買う」
という事は、その日の「引け(前場・後場)」の値を監視してRSIを求め、30を下回っているか?を検証しないといけない。
これを実現するには、
前日にProtraで出来る限り絞った銘柄に関して、引けの10分前ぐらいからPython等で現在値を取得しRSIを求める
などの仕組みが必要となる。
SPY(S&P500ETF)の1銘柄だけにフォーカスしているから実現可能かもしれないけど、全銘柄を対象にすると現実的じゃないな。
バックテスト結果
バックテストは全銘柄で45分、そこそこ早い。
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 |
株価データ: 日足 銘柄リスト: 全銘柄 2000/01/06~2021/06/25における成績です。 ---------------------------------------- 全トレード数 2694 勝ちトレード数(勝率) 1777(65.96%) 負けトレード数(負率) 917(34.04%) 全トレード平均利率 0.63% 勝ちトレード平均利率 3.56% 負けトレード平均損率 -5.04% 勝ちトレード最大利率 38.51% 負けトレード最大損率 -44.32% 全トレード平均期間 8.96 勝ちトレード平均期間 6.00 負けトレード平均期間 14.71 ---------------------------------------- 必要資金 ¥2,846,200 最大ポジション(簿価) ¥2,932,500 最大ポジション(時価) ¥3,001,100 純利益 ¥6,936,643 勝ちトレード総利益 ¥27,816,010 負けトレード総損失 -¥20,879,360 全トレード平均利益 ¥2,575 勝ちトレード平均利益 ¥15,653 負けトレード平均損失 -¥22,769 勝ちトレード最大利益 ¥186,600 負けトレード最大損失 -¥226,000 プロフィットファクター 1.33 最大ドローダウン(簿価) -¥973,100 最大ドローダウン(時価) -¥1,024,800 ---------------------------------------- 現在進行中のトレード数 2 ---------------------------------------- 平均年利 11.08% 平均年利(直近5年) -1.63% 最大連勝 17回 最大連敗 6回 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2021年 45回 ¥93,300円 3.28% 64.44% 1.60倍 -7.18% 2020年 87回 -¥93,770円 -3.29% 62.07% 0.89倍 -28.62% 2019年 90回 -¥152,170円 -5.35% 62.22% 0.80倍 -33.01% 2018年 87回 -¥54,040円 -1.90% 59.77% 0.93倍 -21.43% 2017年 108回 -¥25,420円 -0.89% 66.67% 0.97倍 -25.18% 2016年 96回 ¥387,200円 13.60% 66.67% 1.48倍 -17.55% 2015年 97回 ¥78,800円 2.77% 65.98% 1.09倍 -32.77% 2014年 101回 ¥566,590円 19.91% 75.25% 1.98倍 -13.78% 2013年 117回 ¥1,408,300円 49.48% 69.23% 3.80倍 -10.76% 2012年 108回 ¥605,800円 21.28% 72.22% 2.00倍 -26.00% 2011年 102回 -¥35,005円 -1.23% 61.76% 0.96倍 -17.75% 2010年 92回 ¥616,300円 21.65% 77.17% 1.97倍 -36.27% 2009年 99回 ¥186,790円 6.56% 69.70% 1.19倍 -19.81% 2008年 108回 -¥123,700円 -4.35% 58.33% 0.91倍 -34.68% 2007年 132回 -¥256,932円 -9.03% 59.85% 0.76倍 -18.22% 2006年 162回 ¥41,900円 1.47% 67.28% 1.03倍 -29.91% 2005年 197回 ¥989,700円 34.77% 74.62% 2.26倍 -17.96% 2004年 184回 ¥1,289,000円 45.29% 74.46% 2.34倍 -28.08% 2003年 171回 ¥850,100円 29.87% 76.02% 1.88倍 -25.00% 2002年 145回 -¥218,000円 -7.66% 62.07% 0.85倍 -30.77% 2001年 176回 -¥314,800円 -11.06% 64.20% 0.85倍 -33.14% 2000年 190回 ¥1,096,700円 38.53% 68.42% 1.58倍 -44.32% ---------------------------------------- [年度別ドローダウンレポート] 年度 最大DD(簿価) 最大DD(時価) 2021年 -¥35,700(2021/05/07) -¥7,900(2021/01/08) 2020年 -¥114,200(2020/12/11) -¥19,800(2020/01/16) 2019年 -¥91,900(2019/06/05) -¥16,500(2019/03/28) 2018年 -¥97,200(2018/11/07) -¥31,500(2018/11/07) 2017年 -¥112,600(2017/02/21) -¥30,000(2017/08/10) 2016年 -¥88,500(2016/02/04) -¥72,000(2016/02/04) 2015年 -¥97,000(2015/07/21) -¥40,800(2015/02/17) 2014年 -¥67,600(2014/10/20) -¥32,800(2014/06/20) 2013年 -¥43,500(2013/11/14) -¥53,900(2013/05/21) 2012年 -¥124,000(2012/06/29) -¥16,400(2012/01/16) 2011年 -¥134,400(2011/03/18) -¥24,400(2011/09/06) 2010年 -¥166,500(2010/05/24) -¥61,600(2010/01/29) 2009年 -¥114,300(2009/02/12) -¥32,100(2009/01/05) 2008年 -¥169,800(2008/07/23) -¥98,500(2008/01/15) 2007年 -¥109,900(2007/09/27) -¥32,000(2007/11/05) 2006年 -¥143,000(2006/05/22) -¥52,800(2006/02/17) 2005年 -¥66,000(2005/11/30) -¥50,200(2005/12/12) 2004年 -¥113,200(2004/10/04) -¥32,000(2004/04/19) 2003年 -¥108,000(2003/03/06) -¥77,600(2003/01/20) 2002年 -¥144,000(2002/09/19) -¥53,000(2002/10/23) 2001年 -¥226,000(2001/12/21) -¥80,500(2001/09/17) 2000年 -¥224,000(2000/05/30) -¥75,400(2000/03/13) |
コメントにはドローダウンが気になると書いてあったので、ドローダウンの詳細もつけておいた。
以前、改造した際に付加した情報だが日記が長くなるから省略してたわ。
利益曲線は次の通り。
長い目で見ると増加しているが、書籍に書いているような「勝率9割」には程遠い。
可もなく不可もなく近年の寝てしまう利益曲線の典型的な例のようだ。
SPY(S&P500ETF)って素直なチャートなんだなーー。日本のチャートは難しい。
【2021.07.22】1557 SPDR S&P500 ETF に対してやってみた
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 |
株価データ: 日足 銘柄リスト: デバッグ 2012/03/26~2021/07/13における成績です。 ---------------------------------------- 全トレード数 49 勝ちトレード数(勝率) 40(81.63%) 負けトレード数(負率) 9(18.37%) 全トレード平均利率 0.93% 勝ちトレード平均利率 1.53% 負けトレード平均損率 -1.73% 勝ちトレード最大利率 3.38% 負けトレード最大損率 -4.07% 全トレード平均期間 7.43 勝ちトレード平均期間 5.65 負けトレード平均期間 15.33 ---------------------------------------- 必要資金 ¥994,590 最大ポジション(簿価) ¥998,000 最大ポジション(時価) ¥1,030,400 純利益 ¥284,250 勝ちトレード総利益 ¥435,580 負けトレード総損失 -¥151,330 全トレード平均利益 ¥5,801 勝ちトレード平均利益 ¥10,890 負けトレード平均損失 -¥16,814 勝ちトレード最大利益 ¥33,600 負けトレード最大損失 -¥39,790 プロフィットファクター 2.88 最大ドローダウン(簿価) -¥57,000 最大ドローダウン(時価) -¥92,520 ---------------------------------------- 現在進行中のトレード数 0 ---------------------------------------- 平均年利 3.18% 平均年利(直近5年) 2.19% 最大連勝 9回 最大連敗 2回 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2021年 6回 ¥79,550円 8.00% 100.00% ∞倍 0.00% 2020年 7回 ¥47,300円 4.76% 85.71% 4.83倍 -1.32% 2019年 2回 -¥14,800円 -1.49% 50.00% 0.34倍 -2.34% 2018年 3回 -¥25,200円 -2.53% 66.67% 0.27倍 -3.51% 2017年 6回 ¥22,220円 2.23% 83.33% 3.42倍 -0.92% 2015年 4回 ¥43,320円 4.36% 100.00% ∞倍 0.00% 2014年 8回 ¥6,550円 0.66% 75.00% 1.13倍 -4.07% 2013年 7回 ¥103,050円 10.36% 85.71% 15.81倍 -0.72% 2012年 6回 ¥22,260円 2.24% 66.67% 2.55倍 -0.75% ---------------------------------------- [年度別ドローダウンレポート] 年度 最大DD(簿価) 最大DD(時価) 2021年 ¥0(2021/01/21) ¥0(2021/01/21) 2020年 -¥12,350(2020/11/04) ¥0(2020/01/10) 2019年 ¥9,000(2019/10/10) ¥0(2019/12/10) 2018年 -¥34,500(2018/10/17) ¥0(2018/01/04) 2017年 -¥9,180(2017/11/27) -¥3,400(2017/11/27) 2015年 ¥0(2015/03/17) ¥0(2015/03/17) 2014年 -¥39,790(2014/10/20) -¥230(2014/09/30) 2013年 -¥6,960(2013/10/11) ¥0(2013/01/28) 2012年 -¥7,310(2012/10/03) ¥0(2012/03/28) |
利益曲線は次のとおり。
書籍では90.59%の勝率(平均利益率1.73%)…………ではなく、81.63%の勝率(平均利益率0.93%)だった。
銘柄コード「1557」SPDR S&P500では駄目なのかな?
まとめ
非常に有名な手法のようだけど全く知らなかった。
派生の手法も幾つかあるっぽいので、追って実現してみる……かも。
とりあえずコメント頂いたのはありがたい。
ソースコード
バックテストには無料OSSの「Protra」を利用した。
TIlib、Utility、TrendCheckライブラリはGitHubに置いている。
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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# loop-type: date-only //============================== require "TIlib" require "Utility" require "TrendCheck" //========================================== // RSIパワーゾーンの運用ルール // // 1) 価格が200日単純移動平均線を上回っている。(上昇トレンドの特定) // 2) 4期間RSIが30(25)を下回って引ける // 3) さらに価格が下落し4期間RSIが25(20)を下回って引けたらポジションを2倍にする。 // 4) 4期間RSIが55を上回ったタイミングで売る。 //========================================== codes = CodeList if ($code_num && $code_num != Length(codes)) Print("前回と異なる銘柄リストでは実行できません。") Dummy end $code_num = Length(codes) //グローバル変数を初期化 if (!$__INIT__) $budgetIni = 3000000 $buyUnit = 500000 // 1回の購入資金 (50万円) $MaxHoldDay = 0 // 最大保有日数 $shortSelling = 0 // 空売り戦略 Yes(1)/No(0) $Interest = 1 // 無制限(0) / 単利(1) / 複利(2) $reverse = 0 // 購入順序 昇順(0) / 降順(1) $udcount = 0 // 騰落レシオ利用数 Init() //------------------------------------------------ $MA = [$code_num] $MA_10 = [$code_num] $MA_20 = [$code_num] $RSI = [$code_num] //------------------------------------------------ InitDone() // 騰落レシオ初期化 $__INIT__ = 1 end def Main(i) //================================================== // 条件(買条件, 売条件共通部分) //================================================== //まだ上場していない銘柄は株価データがないためnullが返る if (Index == null) return end if ($order[(int)Code] == -1) $order[(int)Code] = i end if ! ($MA[i] && $RSI[i]) //Tilibのオブジェクト生成 $MA[i] = MA_new(200) // 200日単純移動平均線 $MA_10[i] = {-10}MA_new(200) // 200日単純移動平均線 $MA_20[i] = {-20}MA_new(200) // 200日単純移動平均線 $RSI[i] = RSI_new(4, 0) // RSI(4日) //銘柄ごとのグローバル変数を初期化する $hold[i] = 0 return end //指標の計算を1日進める MA_next($MA[i]) MA_next($MA_10[i]) MA_next($MA_20[i]) RSI_next($RSI[i]) //================================================== // 保有している(追加購入)&していない(新規購入) //================================================== if (! $hold[i] || $hold[i]) if ! (Close && {-1}Close && {-10}Close && {-20}Close) return end ma = MA_value($MA[i]) ma_10 = MA_value($MA_10[i]) ma_20 = MA_value($MA_20[i]) rsi = RSI_value($RSI[i]) if ! (ma && ma_10 && ma_20 && rsi) return end //================================================== // 売買(買い) //================================================== // 1) 価格が200日単純移動平均線を上回っている。(上昇トレンドの特定) flag1 = {-1}Close >= ma && {-10}Close >= ma_10 && {-20}Close >= ma_20 && ma > ma_10 && ma_10 > ma_20 && {-10}Close > {-20}Close && {-1}Close > {-10}Close // 2) 4期間RSIが30(25)を下回って引ける flag2 = rsi < 30 // 3) さらに価格が下落し4期間RSIが25(20)を下回って引けたらポジションを2倍にする。 flag3 = rsi < 25 if ($hold[i] && flag3 && $buyflag[i][2] > 1) PrintLog("ポジションを2倍にする") $buyflag[i][0] = 1 // 購入判断フラグ $buyflag[i][1] = rsi // rsi でソートに利用 $buyCnt = $buyCnt + 1 elsif (! $hold[i] && flag1 && flag2) $buyflag[i][0] = 1 // 購入判断フラグ $buyflag[i][1] = rsi // rsi でソートに利用 $buyflag[i][2] = 1 // 自由利用フラグ $buyCnt = $buyCnt + 1 end end //================================================== // 保有している&本日同一銘柄の買いシグナルが出ていない //================================================== if ($hold[i] && ! $buyflag[i][0]) if ($set[i] < 1) $set[i] = 1 return end $set[i] = $set[i] + 1 rsi = RSI_value($RSI[i]) if ! (rsi) return end //================================================== // 売買(売り) //================================================== // 4) 4期間RSIが55を上回ったタイミングで売る if (rsi >= 55) PrintLog("利食い") $sellflag[i] = 1 $set[i] = 0 end end end //================================================== // 買い(大引けで買う) //================================================== def Buying2(i) if (HasPricedata(Close)) BuyingLimitedPrice(i, 0, Close) end end //==================== // 買い処理 //==================== def SortBuy() if ! (HasPricedata(Close)) return end codeset = $order[(int)Code] // 同購入数のナンピンを行うため、ナンピンでは何もしない if ($buyflag[codeset][2] == 1) $long = 0 $long = Num($buyUnit, Close) $buyflag[codeset][2] = $long else $long = $buyflag[codeset][2] $buyflag[codeset][2] = 0 end Buying2(codeset) end //==================== // 売り処理 //==================== def Sell_(i) if ($sellflag[i]) // 当日のCloseで売る SellingLimitedPrice(i, 0, Close) $sellflag[i] = 0 $buyflag[i][2] = 0 end // 使用した$buyflag 配列を初期化 if ($buyflag[i][0]) $buyflag[i][0] = 0 $buyflag[i][1] = 0 end end //==================== // 銘柄コードを変えながらMain関数,BuySell関数を実行 //==================== Print("-------------------------------------------------") Print("日付 = "+ Year + "/" + Month + "/" + Day) $buyCnt = 0 // 購入数初期化 i = -1 while (i + 1 < $code_num) i = i + 1 {codes[i]}Main(i) end i = 0 if ($buyCnt) sortList = SelectionSort($buyCnt, 0) while i < $buyCnt {sortList[i]}SortBuy() i = i + 1 end end //---------------------------------------------- i = -1 while (i + 1 < $code_num) i = i + 1 {codes[i]}Sell_(i) end |