「ダウの犬」戦略。
米国で運用会社を経営していたマイケル・オヒギンズ氏が1991年に著書「Beating The Dow(邦題:ダウの犬投資法)」で提唱したもの。
毎年1回の銘柄選定により高配当の大型優良株に投資するというシンプルな手法。
投資方法は次の通り。
- NYダウ(ダウ工業株30種平均)採用銘柄(30銘柄)を配当利回りの高い順に並べ、上位10銘柄を選びます。その10銘柄に等金額投資します。
- 1年後に、もう一度NYダウ採用の配当利回り上位10社をスクリーニングします。
- 1年ごとに、上記の方法でリバランス(銘柄入れ替え)を続けます。
このシンプルな投資方法で、NYダウを上回るパフォーマンスを挙げられるらしい。
具体的には過去20年程度のパフォーマンスを計測すると、年率9%、勝率は75%にもなるそうだ。
なぜ配当利回りが高い銘柄に投資をするのか?
理由は配当利回りが高い=株価が低いなので「割安な株」に投資できるから。
配当利回り(%)=1株当たりの年間配当金額 ÷ 1株購入価額 × 100
配当利回りが高い銘柄(ダウの犬)とは「その年に株価が下落した、or あまり上昇しなかった」ダメな銘柄という風に解釈できる。
つまり翌年は反発するだろうという逆張り的な発想
であり、大型優良株で構成するダウ平均なら配当も安定していると考える。
なお、米国では「ダウの犬」手法が広く知られており、実行する人が増え「効果が薄れた」との指摘が多く聞かれているらしい。
特に 2020年は「ダウの犬」による投資収益は-8.0%とNYダウの+9.7%を大きく下回った。
なんだよ……
日本版「ダウの犬」の期待値検証
実はこのダウの犬投資法は、日本株に対しても有効なことが知られている。
長期的な視点で見ればパフォーマンスは良好で、85%にもなるらしい。
「ダウの犬」とは銘柄数などの諸条件が異なるために単純な横比較はできないが、年率リターンも10%近くになり驚異的とのこと。
ただし、2012年以降は目立ったリターンを生み出せず、2018年、2019年はマイナスという結果らしい。
ストラテジーは次のとおり。
【仕掛けのルール】
次の条件を満たす銘柄を年始に50万円上限、軍資金300万円で購入する
- 1) TOPIX Core30のうち、「予想配当利回り」の高い順に並べる
- 2) 予想配当利回りの高い順に並べる
【手仕舞いのルール】
- 1) 大納会である
各年の大納会/年始めは別途カレンダーを見て調査を行った。
また、過去のTOPIX Core30のデータは前回調査済だ。
この一覧に対して過去の会社四季報を調べて「⑥ 配当利回り」を追加した。
……と言いたいところだが、2001年~2010年のデータは下記にあったので、こちらを使っている。
作成したデータはGithubで公開済だ。
バックテスト結果
2001年からバックテストを行った。計算時間は6分。
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 |
株価データ: 日足 銘柄リスト: Core30 2001/01/05~2022/01/04における成績です。 ---------------------------------------- 全トレード数 138 勝ちトレード数(勝率) 78(56.52%) 負けトレード数(負率) 60(43.48%) 全トレード平均利率 5.98% 勝ちトレード平均利率 23.23% 負けトレード平均損率 -16.44% 勝ちトレード最大利率 69.46% 負けトレード最大損率 -90.85% 全トレード平均期間 363.85 勝ちトレード平均期間 363.82 負けトレード平均期間 363.88 ---------------------------------------- 必要資金 ¥3,086,800 最大ポジション(簿価) ¥2,993,000 最大ポジション(時価) ¥3,954,700 純利益 ¥3,526,800 勝ちトレード総利益 ¥7,565,500 負けトレード総損失 -¥4,038,700 全トレード平均利益 ¥25,557 勝ちトレード平均利益 ¥96,994 負けトレード平均損失 -¥67,312 勝ちトレード最大利益 ¥285,900 負けトレード最大損失 -¥361,200 プロフィットファクター 1.87 最大ドローダウン(簿価) -¥1,088,400 最大ドローダウン(時価) -¥1,902,000 ---------------------------------------- 現在進行中のトレード数 8 ---------------------------------------- 平均年利 5.44% 平均年利(直近5年) 0.62% 最大連勝 8回 最大連敗 6回 ---------------------------------------- [年度別レポート] 年度 取引回数 運用損益 年利 勝率 PF 最大DD 2022年 8回 ¥789,400円 25.57% 87.50% 15.92倍 -14.22% 2021年 7回 -¥450,600円 -14.60% 0.00% 0.00倍 -34.80% 2020年 8回 ¥87,400円 2.83% 62.50% 3.17倍 -7.64% 2019年 7回 -¥519,200円 -16.82% 0.00% 0.00倍 -32.27% 2018年 6回 ¥188,900円 6.12% 50.00% 3.63倍 -5.99% 2017年 6回 -¥13,000円 -0.42% 33.33% 0.85倍 -10.08% 2016年 7回 ¥440,500円 14.27% 71.43% 16.90倍 -5.21% 2015年 7回 ¥179,800円 5.82% 85.71% 4.46倍 -11.40% 2014年 7回 ¥1,003,000円 32.49% 85.71% 81.24倍 -3.63% 2013年 6回 ¥371,900円 12.05% 83.33% 4.48倍 -21.94% 2012年 7回 -¥596,400円 -19.32% 42.86% 0.06倍 -90.85% 2011年 7回 ¥45,200円 1.46% 57.14% 1.52倍 -11.40% 2010年 6回 ¥717,900円 23.26% 83.33% 18.09倍 -9.26% 2009年 7回 -¥822,000円 -26.63% 28.57% 0.05倍 -56.99% 2008年 6回 -¥266,400円 -8.63% 16.67% 0.38倍 -29.47% 2007年 7回 ¥742,500円 24.05% 85.71% 22.84倍 -8.27% 2006年 7回 ¥632,000円 20.47% 85.71% 46.14倍 -3.70% 2005年 6回 ¥244,700円 7.93% 83.33% 6.55倍 -11.65% 2004年 6回 ¥683,800円 22.15% 83.33% 11.21倍 -13.35% 2003年 7回 ¥308,200円 9.98% 42.86% 2.94倍 -20.24% 2002年 3回 -¥240,800円 -7.80% 0.00% 0.00倍 -29.22% |
利益曲線は次の通り。
長期スパンで見ると上昇しているが、アメリカ同様で最近は落ち気味だ。
効果が減ったのが偶然なのかは分からない。
おわりに
長期スパンで見ると上昇しているが、今後も上がり続ける保証はない。
そもそも「過去の株価が単調増加だから未来も単調増加の可能性が高い」って……
それって「アナタの感想」ですよね?
© 異世界ひろゆき/西出ケンゴロー/集英社
ギャフン……
© ガラスの仮面/美内すずえ/白泉社
ソースコード
また、バックテストには無料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 "Dow_Core30" // ====================================== // // ====================================== 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 = 3 // 最大保有日数 $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 > 0) $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 //================================================== // 売買(売り) //================================================== flag1 = IsBUYDATE() if (flag1 < 0) PrintLog("手仕舞い") $sellflag[i] = 1 $set[i] = 0 end end end //==================== // 買い処理 //==================== def SortBuy() if ! (HasPricedata(Close)) return end $long = 0 $long = Num($buyUnit, Close) codeset = $order[(int)Code] Buying(codeset) 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 |
Protraのデータを作成するために利用したPythonのコードも公開しておく。
利用したCSVは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 |
import csv 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 read_core30_dau_csv(): s = "" preYear = 2001 num = 1 # for BOM UTF (\ufeff) with open("core30_dow.csv", 'r', encoding="utf-8-sig") as f: next(f) # 一行目飛ばし file_data = f.readlines() for line in file_data: ten = line.replace('\n', '').split(',') # for BOM UTF (\ufeff) with open("dainou.csv", 'r', encoding="utf-8-sig") as csvf: reader = csv.DictReader(csvf) for row in reader: if (int(row['year']) == int(ten[0]) and ten[1] != ""): tmp = create_protra_dataset(ten[1], row['start'], num) s = s + tmp if (row['end'] != ""): tmp = create_protra_dataset(ten[1], row['end'], -1) s = s + tmp num = num + 1 if (int(ten[0]) != preYear): num = 1 preYear = int(ten[0]) return s # Protraの価格リストの読み出し if __name__ == '__main__': s = read_core30_dau_csv() with open("Dow_Core30.pt", mode='w') as f: f.write(merge_protra_dataset(s)) |