台湾出張した際、酒を飲みながら現地技術者が
「将来的にAIでできないことはない!」
と熱く語っていた。
僕「そうだよね!だからAI使って株取引のシステム作成に真面目に取り組んでるよ!」
現地技術者「いや……株取引は別の話。」
多くの人が「全世界株・全米株の長期投資しか勝たん」と言っている時代なので、尚更 システムトレードのストラテジーに関するサイトが減った気がする。
UKI氏なんてシステムトレーダー辞めて絵師になってしまった……。
株取引に関する色々な記事を物色していると、有料記事が目に入った。
株の世界では「株式分割をすると株価が上昇しやすい」という解説をよく目にします。
株式分割は株価にどのような影響を与えるのか、実際のデータで検証してみます。
執筆者は高橋成壽氏。寿FPコンサルティング株式会社代表取締役。
会社のサイトには「一生お金に困らない仕組みを提供いたします」と書いてある。
で、Googleレビュー。
金が絡むと、こんな業者ばっかりやん……
まぁプロなら「本人の分析・考察技術力」はあると思っているので話を続ける。
株式分割は「買い」の有効性検証
Yahoo記事にはどの程度の分析をしたのか一切記載がない。
実際の元記事「四季報オンライン」の無料で読める範囲に次のように書いてあった。
東証1部上場企業のうち、今年2~3月に株式の2分割を公表した企業の株価推移を実際に調べました。
分割公表の前営業日の終値と3月22日の終値を比較し、株価の騰落をまとめると、次のようになりました。
ふんふん。具体的に調べた銘柄は次の「東証一部」だと思われる。
今まで有料記事なんて読んだ事が無いので高橋氏のコンテンツの質の高さは全く分からない。
「経営者の視点から意味を考える」というサブタイトルがついているから、僕のような単なるバックテストの結果論の話ではなく、その先にある背景含めて説明しているのだろう。
ケッ、僕の分析レベルなんてゴミだよ。
© 月見隆士/小学館/史上最強オークさんの楽しい異世界ハーレムづくり(第95話)
まぁ、僕は株式市場の心理どころか相方の心理すらも分からないので、バックテストで検証するだけだ。
検証ルールは、高橋氏の内容を踏まえて次のようにした。
【仕掛けのルール】
- 1) 範囲はプライム市場
- 2) 分割公表の前営業日の終値を利用
- 3) 株式分割は2分割
【手仕舞いのルール】
- 1) 1ヶ月間保有(営業日換算で20日)
2分割に絞っている理由は何故だろうか?
システムトレード無料ツール「Protra」を使って有効性検証してみる
株式分割情報はProtraのファイル「index.txt」内にあるデータを用いる事で抽出が可能だ。
「Protra.Lib/Data/BrandData.cs」のソースコードに、ロジックも記載されている。
1 2 3 4 5 6 7 8 9 10 11 |
if (!entries[i].StartsWith("S:")) throw new ApplicationException("index.txtが不正です。:\n" + line); // 分割比率を処理。 var split = new Split(); var y = int.Parse(entries[i].Substring(2, 4)); var m = int.Parse(entries[i].Substring(6, 2)); var d = int.Parse(entries[i].Substring(8, 2)); split.Date = new DateTime(y, m, d); split.Ratio = double.Parse(entries[i].Substring(11)); brand.Split.Add(split); break; |
要するに、「index.txt」内にあるデータの意味は
1 |
3841,ジーダット,TS,100,S:20130327:100,S:20220330:2 |
証券コード3841の東証スタンダード「ジーダット(最低売買価格100株)」は
- 2013年3月27日に分配比率「1:100」
- 2022年3月30日に分配比率「1:2」
で株式分割を行った事を意味する。
で、次にPythonを使ってProtraでバックテスト可能なデータ作成する。
ソースコードは最後に載せておくが、そのスクリプトを利用すると次のような事が分かった(保有する最古情報は 1983年~)。
内訳 | 銘柄数 | 回数 |
---|---|---|
全株式分割数 | 3883 銘柄 | 9816 回 |
全株式分割数(プライム市場) | 1586 銘柄 | 4854 回 |
全株式分割数(プライム市場で2倍の分割) | 595 銘柄 | 981 回 |
多くの株式会社が株式分割を実施しているし、回数が1度や2度じゃない企業も多い。
バックテスト結果
計算時間は8時間15分。Pythonでの出力しているProtraのスクリプトに無駄が多いために時間がかかってしまっている。
既に売買日時が決まっているので、もっとサクッと終わっても良いはずなのにね。
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 |
株価データ: 日足 銘柄リスト: プライム市場 2000/03/28~2022/07/29における成績です。 ---------------------------------------- 全トレード数 548 勝ちトレード数(勝率) 255(46.53%) 負けトレード数(負率) 293(53.47%) 全トレード平均利率 1.55% 勝ちトレード平均利率 13.66% 負けトレード平均損率 -8.99% 勝ちトレード最大利率 86.44% 負けトレード最大損率 -38.78% 全トレード平均期間 32.44 勝ちトレード平均期間 32.40 負けトレード平均期間 32.47 ---------------------------------------- 必要資金 ¥2,673,000 最大ポジション(簿価) ¥5,181,400 最大ポジション(時価) ¥5,292,800 純利益 ¥4,027,200 勝ちトレード総利益 ¥15,372,800 負けトレード総損失 -¥11,345,600 全トレード平均利益 ¥7,349 勝ちトレード平均利益 ¥60,285 負けトレード平均損失 -¥38,722 勝ちトレード最大利益 ¥428,400 負けトレード最大損失 -¥153,000 プロフィットファクター 1.35 最大ドローダウン(簿価) -¥1,948,100 最大ドローダウン(時価) -¥2,495,900 ---------------------------------------- 現在進行中のトレード数 1 ---------------------------------------- 平均年利 6.55% 平均年利(直近5年) -5.74% 最大連勝 5回 最大連敗 10回 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2022年 13回 -¥238,500円 -8.92% 30.77% 0.39倍 -20.63% 2021年 31回 -¥213,300円 -7.98% 29.03% 0.70倍 -23.36% 2020年 39回 ¥390,900円 14.62% 48.72% 1.41倍 -38.35% 2019年 36回 ¥214,700円 8.03% 33.33% 1.37倍 -17.39% 2018年 45回 -¥921,400円 -34.47% 37.78% 0.42倍 -33.19% 2017年 45回 ¥20,300円 0.76% 46.67% 1.03倍 -29.70% 2016年 33回 -¥244,400円 -9.14% 42.42% 0.70倍 -21.26% 2015年 35回 -¥2,000円 -0.07% 40.00% 1.00倍 -22.98% 2014年 30回 ¥893,200円 33.42% 60.00% 2.88倍 -28.45% 2013年 33回 ¥1,958,400円 73.27% 78.79% 8.56倍 -22.26% 2012年 16回 ¥325,400円 12.17% 62.50% 2.03倍 -21.78% 2011年 15回 ¥31,200円 1.17% 53.33% 1.12倍 -16.35% 2010年 5回 -¥125,000円 -4.68% 20.00% 0.09倍 -10.09% 2009年 6回 -¥84,000円 -3.14% 16.67% 0.23倍 -11.07% 2008年 9回 -¥471,700円 -17.65% 11.11% 0.01倍 -23.20% 2007年 21回 ¥240,300円 8.99% 42.86% 1.49倍 -21.80% 2006年 34回 -¥508,300円 -19.02% 38.24% 0.44倍 -38.78% 2005年 29回 ¥1,087,600円 40.69% 72.41% 7.91倍 -11.78% 2004年 35回 ¥569,400円 21.30% 54.29% 2.18倍 -17.53% 2003年 13回 ¥867,200円 32.44% 84.62% 6.84倍 -17.29% 2002年 14回 ¥116,900円 4.37% 50.00% 1.28倍 -25.70% 2001年 6回 ¥364,500円 13.64% 100.00% ∞倍 0.00% 2000年 5回 -¥244,200円 -9.14% 0.00% 0.00倍 -21.69% |
利益曲線は次の通り。
ありゃりゃ……。予想に反してグニャグニャじゃん。
勝っている時期は、そもそも日経平均株価が上がり調子のタイミングだし、特に「株式分割」を狙うメリットが無いという結果になってしまった。
ストラテジーの拡張(全ての株式分割日の前日に購入)
分配比率「1:2」だけでなく全ての株式分割日の前日に購入した場合も利益曲線はパッとしなかったので次のストラテジーでも検証してみた。
【仕掛けのルール】
- 1) 範囲はプライム市場
- 2) 分割公表の前営業日の終値を利用
- 3)
株式分割は2分割
【手仕舞いのルール】
- 1) 1ヶ月間保有(営業日換算で20日)
1 2 3 4 5 6 7 8 9 10 |
全トレード数 818 勝ちトレード数(勝率) 361(44.13%) 負けトレード数(負率) 457(55.87%) 全トレード平均利率 0.63% 勝ちトレード平均利率 13.81% 負けトレード平均損率 -9.78% 全トレード平均利益 ¥2,496 プロフィットファクター 1.10 |
駄目だこりゃ……。
そもそも株式分割で一ヶ月も株価が上がらないのかもしれない。
ストラテジーの拡張(3日後に売却した場合)
だったら一ヶ月後に売却ではなく、3日後に売却した場合はどうなるだろう?
【仕掛けのルール】
- 1) 範囲はプライム市場
- 2) 分割公表の前営業日の終値を利用
- 3)
株式分割は2分割
【手仕舞いのルール】
- 1) 3日間保有
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 |
株価データ: 日足 銘柄リスト: プライム市場20220403 2000/01/26~2022/08/02における成績です。 ---------------------------------------- 全トレード数 1030 勝ちトレード数(勝率) 478(46.41%) 負けトレード数(負率) 552(53.59%) 全トレード平均利率 1.18% 勝ちトレード平均利率 7.85% 負けトレード平均損率 -4.60% 勝ちトレード最大利率 122.97% 負けトレード最大損率 -25.93% 全トレード平均期間 5.94 勝ちトレード平均期間 5.97 負けトレード平均期間 5.92 ---------------------------------------- 全トレード平均利益 ¥4,871 プロフィットファクター 1.45 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2022年 22回 -¥237,200円 -11.04% 31.82% 0.24倍 -16.18% 2021年 41回 -¥396,900円 -18.47% 24.39% 0.29倍 -10.04% 2020年 49回 -¥375,900円 -17.49% 38.78% 0.54倍 -16.39% 2019年 56回 ¥76,300円 3.55% 51.79% 1.19倍 -20.10% 2018年 80回 -¥178,500円 -8.31% 45.00% 0.80倍 -21.28% 2017年 69回 -¥133,600円 -6.22% 44.93% 0.80倍 -14.37% 2016年 49回 ¥39,200円 1.82% 55.10% 1.11倍 -12.28% 2015年 58回 ¥121,400円 5.65% 44.83% 1.20倍 -16.04% 2014年 60回 ¥1,111,800円 51.74% 55.00% 3.19倍 -15.57% 2013年 68回 -¥577,500円 -26.88% 36.76% 0.50倍 -18.00% 2012年 39回 ¥157,800円 7.34% 48.72% 1.29倍 -13.04% 2011年 35回 ¥160,200円 7.46% 65.71% 1.38倍 -24.76% 2010年 31回 -¥531,200円 -24.72% 38.71% 0.24倍 -25.13% 2009年 13回 -¥129,500円 -6.03% 46.15% 0.46倍 -16.80% 2008年 14回 -¥198,900円 -9.26% 42.86% 0.34倍 -25.93% 2007年 43回 ¥392,900円 18.28% 39.53% 1.81倍 -11.66% 2006年 52回 -¥24,000円 -1.12% 36.54% 0.96倍 -17.19% 2005年 61回 ¥1,266,900円 58.96% 65.57% 4.78倍 -9.17% 2004年 67回 ¥1,275,700円 59.37% 56.72% 4.63倍 -9.52% 2003年 36回 ¥1,325,300円 61.68% 58.33% 6.17倍 -10.47% 2002年 32回 ¥368,800円 17.16% 53.13% 1.90倍 -21.30% 2001年 27回 ¥477,300円 22.21% 62.96% 3.00倍 -12.85% 2000年 28回 ¥1,026,800円 47.78% 82.14% 9.30倍 -15.45% |
利益曲線は次の通り。
今までの結果よりマシな結果になった。
でも2006年以降はどちらにせよパッとしないね。
多くの人に認識されている材料だから、最近は既に織り込み済みなのかもしれない。
ストラテジーの拡張(株式分割の1ヶ月前に購入した場合)
「織り込み済」ならば、株式分割前日でなく一ヶ月前に購入した場合のバックテストを実施してみる。
【仕掛けのルール】
- 1) 範囲はプライム市場
- 2) 分割実施の一ヶ月前の終値を利用
【手仕舞いのルール】
- 1) 2ヶ月間保有
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 |
全トレード数 954 勝ちトレード数(勝率) 507(53.14%) 負けトレード数(負率) 447(46.86%) 全トレード平均利率 5.92% 勝ちトレード平均利率 20.80% 負けトレード平均損率 -10.95% 勝ちトレード最大利率 184.55% 負けトレード最大損率 -58.28% 全トレード平均期間 53.25 ---------------------------------------- 全トレード平均利益 ¥27,608 プロフィットファクター 2.24 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2022年 21回 -¥427,200円 -9.65% 42.86% 0.42倍 -36.52% 2021年 40回 ¥497,500円 11.23% 47.50% 1.62倍 -39.62% 2020年 48回 ¥1,941,400円 43.84% 50.00% 2.29倍 -58.28% 2019年 54回 ¥1,459,300円 32.95% 53.70% 2.33倍 -27.67% 2018年 69回 ¥167,900円 3.79% 37.68% 1.08倍 -35.13% 2017年 65回 ¥3,205,600円 72.38% 61.54% 6.89倍 -16.24% 2016年 47回 ¥332,500円 7.51% 53.19% 1.32倍 -35.77% 2015年 57回 ¥667,700円 15.08% 42.11% 1.56倍 -30.78% 2014年 56回 ¥1,707,000円 38.54% 53.57% 2.43倍 -40.00% 2013年 62回 ¥3,921,000円 88.54% 67.74% 4.67倍 -31.41% 2012年 37回 ¥1,959,100円 44.24% 62.16% 3.68倍 -25.74% 2011年 32回 -¥308,400円 -6.96% 50.00% 0.72倍 -43.70% 2010年 29回 -¥49,000円 -1.11% 51.72% 0.95倍 -38.22% 2009年 21回 ¥1,091,800円 24.65% 66.67% 3.24倍 -27.27% 2008年 18回 -¥912,400円 -20.60% 22.22% 0.23倍 -40.97% 2007年 45回 ¥131,500円 2.97% 40.00% 1.10倍 -37.97% 2006年 52回 -¥787,200円 -17.77% 38.46% 0.53倍 -41.97% 2005年 54回 ¥4,181,800円 94.43% 79.63% 13.71倍 -12.71% 2004年 59回 ¥3,414,900円 77.11% 67.80% 6.37倍 -19.00% 2003年 32回 ¥2,977,200円 67.23% 65.63% 12.98倍 -13.25% 2002年 33回 ¥1,088,200円 24.57% 57.58% 2.44倍 -45.41% 2001年 23回 ¥78,000円 1.76% 60.87% 1.16倍 -33.09% |
利益曲線は次の通り。
おお!ほぼ担当増加!
ただ、株式分割情報がいつのタイミングで発表されるのかは企業によって異なる。
もう少し検討が必要かもしれないが次に繋がる結果となった。
おわりに
「株式分割は買い材料」と認識される理由としてよく言われているのは次の2つ。
株式の需給面に着目した視点 | 元株取得のハードルが下がることで、新たな投資家が入って来やすくなるため |
---|---|
企業の成長性に着目した視点 | 企業経営陣が先行きに自信を持っていると受け止められるため |
高橋氏のやり方ではバックテストの結果はパッとしない結果となってしまった。
発表直後に購入すれば上昇チャンスはあるのかもしれない。もう少し調査が必要そうだ。
ソースコード
「index.txt」ファイルから「Protra」用のファイルに変換するコードは次のとおり。
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 |
import datetime # Protraファイルの作成 def create_protra_dataset(code, date, order): s = "" s += " if ((int)Code == " + code + ")\n" s += " if ( \\\n" (year, month, day) = date.split('/') s += "(Year == " + str(int(year)) + " && Month == " + str(int(month)) + " && Day == " + str(int(day)) + ") || \\\n" s += " (Year == 3000))\n" s += " return " + str(int(order)) + "\n" s += " end\n" s += " end\n" return s def merge_protra_dataset(s): a = "def IsBUYDATE\n" b = " return 0\n" b += "end\n" return a + s + b # CSVの読み込み def convert_date(str): tmp = str.split(':')[1] return tmp[0:4] + "/" + tmp[4:6] + "/" + tmp[6:8] # CSVの読み込み def read_index(): s = "" with open("index.txt", 'r') as f: # 一行飛ばす next(f) file_data = f.readlines() for line in file_data: tmp = line.replace('\n', '').split(',') # 株式分割のみ抽出 if('TP' in tmp[2]): for i in range(1, len(tmp)): if('S:' in tmp[i]): if('2' == tmp[i].split(':')[2]): con = create_protra_dataset(tmp[0], convert_date(tmp[i]), "1") s = s + con return s # Protraの価格リストの読み出し if __name__ == '__main__': s = read_index() with open("Bunkatsu.pt", mode='w') as f: f.write(merge_protra_dataset(s)) |
また、バックテストには無料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 |
# loop-type: date-only //============================== require "TIlib" require "Utility" require "TrendCheck" require "Bunkatsu" // ====================================== // // ====================================== codes = CodeList if ($code_num && $code_num != Length(codes)) Print("前回と異なる銘柄リストでは実行できません。") Dummy end $code_num = Length(codes) //グローバル変数を初期化 if (!$__INIT__) $budgetIni = 3000000 $buyUnit = 500000 // 1回の購入資金 (300万円) $MaxHoldDay = 20 // 最大保有日数 $shortSelling = 0 // 空売り戦略 Yes(1)/No(0) $Interest = 1 // 無制限(0) / 単利(1) / 複利(2) $reverse = 0 // 購入順序 昇順(0) / 降順(1) $udcount = 0 // 騰落レシオ利用数 Init() //------------------------------------------------ //------------------------------------------------ InitDone() // 騰落レシオ初期化 $__INIT__ = 1 end def Main(i) //================================================== // 条件(買条件, 売条件共通部分) //================================================== //まだ上場していない銘柄は株価データがないためnullが返る if (Index == null) return end if ($order[(int)Code] == -1) $hold[i] = 0 $order[(int)Code] = i end //================================================== // 保有してない→購入 //================================================== if (! $hold[i]) //================================================== // 売買(買い) //================================================== flag1 = IsBUYDATE() if (flag1) $buyflag[i][0] = 1 $buyflag[i][1] = flag1 // 好きなパラメータをもとにソート $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 //================================================== // 売買(売り) //================================================== if ($set[i] >= $MaxHoldDay) PrintLog("手仕舞い") $sellflag[i] = 1 $set[i] = 0 end end end //==================== // 買い処理 //==================== def SortBuy() if ! (HasPricedata({-1}Close)) return end $long = 0 $long = Num($buyUnit, {-1}Close) codeset = $order[(int)Code] // Buying(codeset) BuyingLimitedPrice(codeset, -1, {-1}Close) end //==================== // 売り処理 //==================== def Sell_(i) if ($sellflag[i]) 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 // 購入数初期化 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 |