秋と言えばスポーツ、読書!
って誰が言い出したのか?
と思ってググったら次のように書いてあるサイトが多かった。
○○の秋 | きっかけ | 詳細 |
---|---|---|
スポーツの秋 | 東京オリンピック | 「体育の日(スポーツの日)」を中心としてスポーツを楽しむ風潮が生まれ、運動会も秋に行われることが多くなったため |
読書の秋 | 夏目漱石 | 韓愈文人が詠んだ、「灯火親しむべし」という詩を「三四郎」で取り上げたため |
食欲の秋 | 季節に応じた収穫 | 四季の中で一番食べ物を豊富に収穫できる季節が「秋」だった |
収穫の秋 | 季節に応じた収穫 | 四季の中で一番食べ物を豊富に収穫できる季節が「秋」だった |
美術の秋 | 11月3日(文化の日) | 1918年に発行された『新潮』という雑誌で使用 |
あまり歴史的な背景は無さそうなので詳細調査はする気にならないけどね。
最近は釣り三昧で、システムトレードの事は微塵も思い出さなくなった。
確かに「システムトレード」の記事のアクセス数は高い。
けど、アクセス数が高いのは投稿して数ヶ月程度で、その後は伸びない。
そもそも日本でシステムトレードに取り組んでいる人が少ない(母集団が少ない)のだろうね。
ロングテールで考えると、調査報告記事の方がアクセス数を稼いでくれる。
ヒストリカルボラティリティを何度か実装したことで、ある程度理解できた。
だったら、斉藤正章氏の順張りを再度やってみよう。
2年前に実装した時は失敗してしまった。
今度こそバックテストを成功させてみる!
まずはおさらい「順張り買い」戦略
斉藤正章氏の逆張りは有名だが、順張りはこの手法で初めて知った。
【仕掛け条件】
次をすべて満たすとき、翌日成行で仕掛ける。
- 1) 過去500日間のボラティリティがX%以上(10%~20%)
- 2) 過去100日間のボラティリティがY%より小さい(1%~9%)
- 3) 終値が過去50日間の最高値を更新(レンジを上抜けした銘柄を選ぶ)
- 4) 終値が過去50日間の終値の最高値を更新した銘柄が、市場全体で50銘柄以上ある場合
ここで、X%の部分は10%~20%、Y%の部分は1%~9%の数値との事。
この2つの条件で、「もともと値動きがあった銘柄が、直近2~3ヶ月間は値動きが乏しく、もみ合いの状態が続いている」銘柄を探している。
【手仕舞い条件】
以下のいずれかを満たすとき、翌日成行で手仕舞いとなる。
- 利食い:終値と3日移動平均乖離率が+15%以上になった場合
- 損切り:終値が過去20日間の終値の最安値を更新した場合
斉藤氏の実パラメータは秘密との事でヒントとして
X%の部分は10%~20%、Y%の部分は1%~9%の数値
と書かれている。
が、この数値範囲では銘柄が全く抽出できなかった。
今回は実装を見直したところ動作した。
バックテスト結果
どのパラメータが最適なのか分からない。
とりあえず2種類やってみた。
過去100日間のHVが9%より小さい&過去500日間のHVが20%以上の場合
計算時間は全銘柄で5時間40分。
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 |
株価データ: 日足 銘柄リスト: 全銘柄 2001/03/12~2021/08/20における成績です。 ---------------------------------------- 全トレード数 571 勝ちトレード数(勝率) 238(41.68%) 負けトレード数(負率) 333(58.32%) 全トレード平均利率 1.53% 勝ちトレード平均利率 7.93% 負けトレード平均損率 -3.04% 勝ちトレード最大利率 81.92% 負けトレード最大損率 -15.35% 全トレード平均期間 49.60 勝ちトレード平均期間 78.36 負けトレード平均期間 29.05 ---------------------------------------- 必要資金 ¥2,989,200 最大ポジション(簿価) ¥2,999,800 最大ポジション(時価) ¥4,036,000 純利益 ¥3,853,014 勝ちトレード総利益 ¥8,274,624 負けトレード総損失 -¥4,421,610 全トレード平均利益 ¥6,748 勝ちトレード平均利益 ¥34,767 負けトレード平均損失 -¥13,278 勝ちトレード最大利益 ¥349,000 負けトレード最大損失 -¥69,700 プロフィットファクター 1.87 最大ドローダウン(簿価) -¥664,400 最大ドローダウン(時価) -¥834,200 ---------------------------------------- 現在進行中のトレード数 7 ---------------------------------------- 平均年利 6.14% 平均年利(直近5年) 8.98% 最大連勝 6回 最大連敗 9回 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2021年 22回 ¥261,620円 8.75% 40.91% 2.57倍 -7.36% 2020年 23回 ¥114,440円 3.83% 43.48% 1.43倍 -9.06% 2019年 23回 ¥50,724円 1.70% 52.17% 1.33倍 -6.69% 2018年 53回 ¥165,050円 5.52% 35.85% 1.34倍 -8.33% 2017年 40回 ¥750,500円 25.11% 55.00% 4.08倍 -9.97% 2016年 25回 -¥156,260円 -5.23% 24.00% 0.36倍 -7.82% 2015年 37回 ¥524,400円 17.54% 59.46% 3.13倍 -7.64% 2014年 39回 ¥284,240円 9.51% 46.15% 2.10倍 -6.33% 2013年 27回 ¥814,100円 27.23% 51.85% 5.39倍 -8.13% 2012年 42回 -¥95,700円 -3.20% 42.86% 0.76倍 -8.82% 2011年 27回 -¥138,800円 -4.64% 29.63% 0.70倍 -15.35% 2010年 40回 -¥118,300円 -3.96% 35.00% 0.50倍 -6.54% 2009年 20回 -¥19,800円 -0.66% 40.00% 0.87倍 -4.91% 2008年 7回 -¥51,100円 -1.71% 14.29% 0.00倍 -3.21% 2007年 34回 -¥81,700円 -2.73% 32.35% 0.70倍 -11.01% 2006年 10回 ¥616,500円 20.62% 70.00% 18.03倍 -3.65% 2005年 26回 ¥751,700円 25.15% 61.54% 7.22倍 -6.38% 2004年 40回 ¥31,400円 1.05% 37.50% 1.12倍 -6.01% 2003年 28回 ¥197,800円 6.62% 57.14% 2.64倍 -5.73% 2002年 6回 -¥50,400円 -1.69% 16.67% 0.00倍 -5.14% 2001年 2回 ¥2,600円 0.09% 50.00% 1.14倍 -4.81% |
利益曲線は次のとおり。
トータルでは上昇しているが、耐えるべき年が多いな。
本番で利用するには現実的じゃない。
過去100日間のHVが5%より小さい&過去500日間のHVが20%以上の場合
こちらも計算時間は全銘柄で5時間40分。
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 |
株価データ: 日足 銘柄リスト: 全銘柄 2003/09/17~2021/07/30における成績です。 ---------------------------------------- 全トレード数 108 勝ちトレード数(勝率) 47(43.52%) 負けトレード数(負率) 61(56.48%) 全トレード平均利率 2.75% 勝ちトレード平均利率 8.69% 負けトレード平均損率 -1.83% 勝ちトレード最大利率 79.19% 負けトレード最大損率 -6.76% 全トレード平均期間 52.55 勝ちトレード平均期間 84.51 負けトレード平均期間 27.92 ---------------------------------------- 必要資金 ¥2,240,400 最大ポジション(簿価) ¥2,986,000 最大ポジション(時価) ¥3,559,500 純利益 ¥1,269,640 勝ちトレード総利益 ¥1,752,040 負けトレード総損失 -¥482,400 全トレード平均利益 ¥11,756 勝ちトレード平均利益 ¥37,277 負けトレード平均損失 -¥7,908 勝ちトレード最大利益 ¥342,500 負けトレード最大損失 -¥33,350 プロフィットファクター 3.63 最大ドローダウン(簿価) -¥84,800 最大ドローダウン(時価) -¥229,700 ---------------------------------------- 現在進行中のトレード数 7 ---------------------------------------- 平均年利 3.33% 平均年利(直近5年) 4.22% 最大連勝 6回 最大連敗 9回 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2021年 7回 -¥5,100円 -0.23% 42.86% 0.83倍 -4.21% 2020年 6回 -¥15,500円 -0.69% 33.33% 0.61倍 -3.06% 2019年 5回 ¥48,700円 2.17% 20.00% 8.16倍 -0.66% 2018年 10回 ¥341,550円 15.25% 70.00% 8.84倍 -6.76% 2017年 22回 ¥103,300円 4.61% 45.45% 2.07倍 -5.20% 2016年 1回 ¥2,500円 0.11% 100.00% ∞倍 0.00% 2015年 11回 ¥194,800円 8.69% 54.55% 6.49倍 -3.31% 2014年 13回 ¥70,690円 3.16% 46.15% 2.28倍 -3.21% 2013年 8回 ¥207,300円 9.25% 50.00% 6.07倍 -2.74% 2012年 7回 ¥48,400円 2.16% 42.86% 1.89倍 -5.28% 2011年 1回 -¥1,000円 -0.04% 0.00% 0.00倍 -0.23% 2010年 4回 -¥29,400円 -1.31% 25.00% 0.06倍 -3.32% 2007年 2回 -¥400円 -0.02% 50.00% 0.00倍 -0.10% 2006年 1回 -¥8,700円 -0.39% 0.00% 0.00倍 -2.14% 2005年 7回 ¥323,300円 14.43% 42.86% 13.34倍 -2.61% 2004年 2回 -¥300円 -0.01% 50.00% 0.83倍 -0.40% 2003年 1回 -¥10,500円 -0.47% 0.00% 0.00倍 -2.48% |
利益曲線は次のとおり。
数値を絞れば安定感は上がった。
けど取引数が大幅に下がってしまった。
にも関わらず、保有期間が3ヶ月近いので資金繰りも悪い。
まとめ
当時諦めた順張りのシステムトレードのストラテジーを実装して結果を得ることができた。
結果としては当時とそんなに変わらない利益曲線になった気がする……。
結局、パラメーターがよく分からなかっただけで計算自体は合ってたのかもしれない。
ソースコード
バックテストには無料OSSの「Protra」を利用した。
TIlib、Utility、TrendCheck、TOPIXライブラリは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 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# loop-type: date-only //============================== require "TIlib" require "Utility" require "TrendCheck" //========================================== // //【買いルール】 // // 1) 株価が100円以上 // 2) 20日平均売買代金が2億円以上 // 3) 100日ヒストリカルボラティリティが30以上 // 4) ADX(10,5)が30以上# loop-type: date-only //============================== require "TIlib" require "Utility" require "TrendCheck" //============================== // 「順張り買い」戦略(斉藤正章) // 株価のブレイクアウトを利用して収益をあげる「順張り買い」戦略 // https://toushi-kyokasho.com/system-trade/ //------------------------------ // // 【買いルール】 // 1) 過去500日間のボラティリティがX%以上(10%~20%) // 2) 過去100日間のボラティリティがY%より小さい(1%~9%) // 3) 終値が過去50日間の最高値を更新(レンジを上抜けした銘柄を選ぶ) // 4) 終値が過去50日間の終値の最高値を更新した銘柄が、市場全体で50銘柄以上ある場合 // // 【手仕舞いルール】 // 1) 利食い:終値と3日移動平均乖離率が+15%以上になった場合 // 2) 損切り:終値が過去20日間の終値の最安値を更新した場合 // //========================================== 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() //------------------------------------------------ $BB3 = [$code_num] //------------------------------------------------ InitDone() // 騰落レシオ初期化 $__INIT__ = 1 end //================================================== // 終値が過去50日間の終値の最高値を更新した銘柄数 //================================================== def HighMaxNum(num) $ratio = 0 if ! (Index > num) return end c = 1301 while (c < 9999) cc = (string)c i = 1 flag = 1 while (i < num) if (! {-i}{cc}Close || !{cc}Close || {-i}{cc}Close >= {cc}Close) flag = 0 break end i = i + 1 end c = c + 1 if (flag) $ratio = $ratio + 1 if ($ratio > 50) break end end end Print("-------------------------------------------------") Print("日付 = "+ Year + "/" + Month + "/" + Day) Print("過去50日間の終値の最高値を更新した銘柄数 = "+ $ratio) end // 価格変動率 def DayBefore(i) // 前日比 = (終値) ÷ 1日前の終値 return Log((float){i}Close / (float){i - 1}Close ) end // ヒストリカル・ボラティリティ // hv = Math.sqrt(250) * closes[-101..-1].log.dev(100)[-1] * 100 // HV = √250 * 1日あたりのヒストリカルボラティリティ * 100 // 過去20日分(log|今日の価格(株価)÷昨日の価格(株価) |) def CalcHV(num) // 1日あたりのヒストリカルボラティリティ day_hv = 0 a1 = 0 a2 = 0 c = 0 while (c < num) if ! ({(int)(c * -1)}Close && {(int)(c * -1 - 1)}Close) return 0 end a0 = DayBefore(c * -1) a1 = a0 * a0 + a1 a2 = a0 + a2 c = c + 1 end // 標準偏差 = √Σ(a_i - a)^2/N = Σa_i^2/N - (Σa_i/N)^2 day_hv = Sqrt(a1 / (float)num - (a2 / (float)num) * (a2 / (float)num)) // num日数の平方根 × 1日あたりのヒストリカルボラティリティ × 100 return Sqrt(num) * day_hv * 100 end def Main(i) //================================================== // 条件(買条件, 売条件共通部分) //================================================== //まだ上場していない銘柄は株価データがないためnullが返る if (Index == null) return end if ($order[(int)Code] == -1) $order[(int)Code] = i end if ! ($BB3[i]) // 銘柄ごとのグローバル変数を初期化する $BB3[i] = BB_new(3) // 3日移動平均線乖離率 $hold[i] = 0 return end //指標の計算を1日進める BB_next($BB3[i]) //================================================== // 保有してない→購入 //================================================== if (! $hold[i]) if ! (Close) return end //================================================== // 売買(買い) //================================================== // 4) 終値が過去50日間の終値の最高値を更新した銘柄が、市場全体で50銘柄以上ある場合 if ! ($ratio >= 50) return end // 2) 過去100日間のボラティリティがY%より小さい(1%~9%) flag2 = CalcHV(100) if ! (9 > flag2) return end // 1) 過去500日間のボラティリティがX%以上(10%~20%) flag1 = CalcHV(500) if ! (flag1 >= 20) return end // 3) 終値が過去50日間の最高値を更新(レンジを上抜けした銘柄を選ぶ) if ! (Index > 50) return end c = 1 flag3 = 1 while (c < 50) if ! (Close > {-1 * c}High) flag3 = 0 break end c = c + 1 end if (flag3) PrintLog("買い候補") Print(flag1) Print(flag2) $buyflag[i][0] = 1 $buyflag[i][1] = Close $buyflag[i][2] = 1 $buyCnt = $buyCnt + 1 end //================================================== // 保有している→売却 //================================================== elsif ($hold[i]) if ($set[i] < 1) $set[i] = 1 return end $set[i] = $set[i] + 1 //================================================== // 売買(売り) //================================================== ma3 = BB_value($BB3[i]) if ! (ma3) return end r3 = 100*(Close - ma3)/ma3 c = 1 low = Close while c < 20 if {-c}Close < low low = {-c}Close end c = c + 1 end // 1) 利食い:終値と3日移動平均乖離率が+15%以上になった場合 if (r3 >= 15) PrintLog("利食い") $sellflag[i] = 1 $set[i] = 0 // 2) 損切り:終値が過去20日間の終値の最安値を更新した場合 elsif (low >= Close) PrintLog("手仕舞い") $sellflag[i] = 1 $set[i] = 0 end end end def CheckHighLow2(t) t = Yobine(t, 0) if ! ({1}High > t && t > {1}Low) return 0 end if (t > {1}Open) return 0 else return t end end //==================== // 買い処理 //==================== def SortBuy() if ! (HasPricedata({1}Open)) return end $long = 0 $long = Num($buyUnit, Close) codeset = $order[(int)Code] Buying(codeset) end //==================== // 売り処理 //==================== def Sell_(i) if ($sellflag[i]) // 当日のCloseで売る Selling(i) $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 // 購入数初期化 //4) 終値が過去50日間の終値の最高値を更新した銘柄が、市場全体で50銘柄以上ある場合 HighMaxNum(50) i = -1 while (i + 1 < $code_num) i = i + 1 {codes[i]}Main(i) end i = 0 if ($buyCnt) sortList = SelectionSort(10, 0) cnt = $buyCnt if ($buyCnt > 10) cnt = 10 end while i < cnt {sortList[i]}SortBuy() i = i + 1 end end //---------------------------------------------- i = -1 while (i + 1 < $code_num) i = i + 1 {codes[i]}Sell_(i) end |