株のルールは単純なゲームです。
株が上がるのは、誰かが売りよりたくさん買ったからでしかなく、買いよりたくさん売れば下がるだけです。
テクニカル分析は単なるオカルトに過ぎず、チャートを分析したところで将来の株価を完璧に予測することは不可能です。
そんなチャート分析の中でも、シンプルな手法でありながら絶大な効果があると大人気な手法があります。
それが「グランビルの法則」です。
おさらい・・・グランビルの法則とは?
アメリカの金融ライターであり、投資セミナー講釈家のジョセフのジョセフ・E・グランビル(Joseph E. Granville)が考案しました。
新聞社ハットン・デイリー・マーケット・ワイヤー通信社の金融記者で、地元では弱気のニュースレター屋として有名です。
海外のサイトで出てくる情報は次のようなものぐらいです。
投資セミナーでは棺桶から飛び出したり、顧客に会う際にはプールの水面を歩くように見せかけたりとショーマンとして有名。
by Wikipedia
また、グランビル氏はハルバード金融ダイジェストのパフォーマンスでは、1年あたり20パーセント以上の損失を出し、最下位(25年に渡りほぼ最下位)でした。
そんな彼が、1962年に、チャート分析本「A Strategy of Daily Stock Market Timing for Maximum Profit」を発表し、日本では「グランビルの投資法則―株価変動を最大に活用する戦略」という名前で出版しました。
本に関して、本人は次のように語っています。
ニューヨーク証券取引所のトイレで壁の模様が株価に見えた。
その壁の模様のシワが移動平均線に見えた。
株価が移動平均線を突き抜けているように見えたのを本にしたら売れるのではないかと考えた。
グランビルの法則は世界的には無名です。
日本人のみに浸透したオカルト法則・・・というのが真実です。
グランビルの8つの法則は何か?
- 移動平均線が下落から横ばいに転じた後、株価がその移動平均線を上抜いたら買い。
- 上昇中の移動平均線を株価が下回った後、反発したら買い。
- 株価が移動平均線より上にあり、上昇中の移動平均線を割り込むことなく反発したら買い。
- 下降中の移動平均線より株価が大きく下へと乖離したら買い
売りは上記の買いポイントを逆にしたもので、合計8つの法則が出来上がります。
この「グランビルの法則」はどういうわけだか、とりわけ日本では権威あるテクニカル分析として認識されています。
グランビルの法則のシステムトレード化
「法則」と名前がついていますが、これを実装するのは容易ではありません。
そこで、グランビルもどきのシステムトレードが幾つか存在します。
グランビルもどきの法則(Hiroさん版)
【買いルール】
- 1. 株価(終値)が3日間、連続して、前日より下がっている
- 2. 25日移動平均と75日平均が、上昇中である
- 3. 5日移動平均>25日移動平均>75日移動平均である
- 4. 終値は、25日移動平均より上にある
【手仕舞いルール】
- 1. 高値が買値+2%を越えた時、翌日の寄付きで売る
- 2. 実働10日(≒カレンダーで14日経過)で売る
こちらはバックテストを実施した事があります。
【参考】グランビルもどきの法則の有効性検証(protraシストレ)
グランビルもどきの法則(じんぱちさん版)
じんぱちのシステムトレード実践日記に書かれている「グランビルの法則のシステム化」を参考にします。
2年前に実装してみたかった手法です。
【買いルール】
- 移動平均100日 上向き
- 出来高移動平均50日 上向き
- *************が****より大きい
- 移動平均3日が期間安値3日移動平均10日より小さい
【手仕舞いルール】
- 1. 高値が買値+2%を越えた時、翌日の寄付きで売る
- 2. 実働10日(≒カレンダーで14日経過)で売る
こちらイザナミというツールを使って実装しており「期間安値移動平均(期間3日、移動平均10日)」をサポートラインとして使っています。
これにより、勝率70.12% PF2.69を実現しているとの事です。
じんぱち氏風グランビルの法則の有効性の検証
実現するには2つの問題点があります。
まず、「期間安値移動平均」というものがProtraには存在しません。
また、「*************が****より大きい」という伏せ字が分かりません。
期間安値移動平均を何にするか?
「TIlib.pt」を修正して作ってみるか・・・・と思っていたら、近いテクニカル指標があることが分かりました。
それが「HL(高値・安値)バンド」です。
「HL(高値・安値)バンド」とは、リチャード・ドンチャン氏が提唱したもので「過去n日間における高値・安値同士を線で結びんだグラフ」です。
高値同士を結んだ線を「ハイ(High)の線(Hバンド)」、安値同士を結んだ線を「ローの線(Lバンド)」と呼びます。
このHL Band(期間3日)のローの線をサポートラインとして使えば、多少近い形になるのでは?と考えました。
「**が**より大きい」を何にするか?
昔イザナミの公式サイトに掲載されていたというグランビルの法則を実装した結果です。
これを見ると、「25日移動平均線が終値より大きい」というのが一つの追加すべき指標に感じます。
*************(13文字)が****(4文字)より大きい
25にちいどうへいきんせん(13文字)おわりね(4文字)より大きい
と、文字数も伏せ数と一致してます。
採用したルールとソースコード
まとめると、次のようになります。
【買いルール】
- 移動平均100日が上向き
- 出来高移動平均50日が上向き
- 25日移動平均線が終値より大きい
- 移動平均3日がHL Band(3日)のLバンドより小さい
【手仕舞いルール】
- 利食い:終値と移動平均(5日)との乖離率が0%以上
- 利食い:含み益が10%を上回った
- 損切り:実働10日(≒カレンダーで14日)経過
手仕舞いルールは記載がありません。
「終値と移動平均(5日)との乖離率が0%以上」は、結果のドローダウンが大きかったので追加しました。
ソースコード
Utility.ptは、「過去の日記」を参照してください。
TrendCheck.pt も、次のようなゴクウさんのソースコードを拝借して使っています。
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 |
//================================================== // 現在の株価が最高値,最安値の中間値より大きい場合、現在その株価は上昇トレンドにある //================================================== def StockPosition(i) if ! $__INITSP__ $HL = [$code_num] $__INITSP__ = 1 end if ! $HL[i] //Tilibのオブジェクト生成 stockPositionDay = 75 $HL[i] = HighLow_new(stockPositionDay) return 0 end //指標の計算を1日進める HighLow_next($HL[i]) highest = HighLow_high($HL[i]) lowest = HighLow_low($HL[i]) if !highest || !lowest return 0 end // 過去75日の最大、最小値の中間価を算出 threshold = lowest + (highest-lowest)/100 * 50 // 当日の株価位置がしきい値より大きければ1を返す return Close > threshold end |
売買ロジック部分のコードは次のようになります。
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 |
# loop-type: date-only //============================== require "TIlib" require "Utility" require "TrendCheck" //============================== // じんぱち氏風グランビルの法則もどき //------------------------------ // // 【買いルール】 // 1) 移動平均100日が上向き(当日 > 5日前 > 10日前) // 2) 出来高移動平均50日が上向き(当日 > 5日前 > 10日前) // 3) 終値が25日移動平均より大きい // 4) 移動平均3日がHL Band(3日)のLバンドより小さい // // 【手仕舞いルール】 // 1) 利食い:終値と移動平均(5日)との乖離率が0%以上 // 2) 利食い:含み益が10%を上回った // 3) 損切り:実働10日(≒カレンダーで14日)経過 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 = 10 // 最大保有日数 $Interest = 0 // 無制限(0) / 単利(1) / 複利(2) //------------------------------------------------ $set = [$code_num] $buy = [$code_num] $hold = [$code_num] //------------------------------------------------ $MA100 = [Length(CodeList)] $MA100_5 = [Length(CodeList)] $MA100_10 = [Length(CodeList)] $VMA50 = [Length(CodeList)] $VMA50_5 = [Length(CodeList)] $VMA50_10 = [Length(CodeList)] $MA3 = [Length(CodeList)] $MA25 = [Length(CodeList)] $HLB = [Length(CodeList)] $BB5 = [Length(CodeList)] // 値上がり銘柄のカウント ------------------------ $buyflag = [$code_num] $sellflag = [$code_num] $cnt = 0 $__INIT__ = 1 end def Main(i) //================================================== // 条件(買条件, 売条件共通部分) //================================================== //まだ上場していない銘柄は株価データがないためnullが返る if (Index == null) return end if ! $MA100[i] //Tilibのオブジェクト生成 $MA100[i] = MA_new(100) $MA100_5[i] = {-5}MA_new(100) $MA100_10[i] = {-10}MA_new(100) $MA3[i] = MA_new(3) $MA25[i] = MA_new(25) $HLB[i] = HLBand_new(3) $BB5[i] = BB_new(5) $VMA50[i] = VolumeMA_new(50) $VMA50_5[i] = {-5}VolumeMA_new(50) $VMA50_10[i] = {-10}VolumeMA_new(50) //銘柄ごとのグローバル変数を初期化する $hold[i] = 0 return end //指標の計算を1日進める MA_next($MA100[i]) MA_next($MA100_5[i]) MA_next($MA100_10[i]) MA_next($MA3[i]) MA_next($MA25[i]) BB_next($BB5[i]) HLBand_next($HLB[i]) VolumeMA_next($VMA50[i]) VolumeMA_next($VMA50_5[i]) VolumeMA_next($VMA50_10[i]) ma100 = MA_value($MA100[i]) ma100_5 = MA_value($MA100_5[i]) ma100_10 = MA_value($MA100_10[i]) ma3 = MA_value($MA3[i]) ma25 = MA_value($MA25[i]) ma5 = BB_value($BB5[i]) vma50 = VolumeMA_value($VMA50[i]) vma50_5 = VolumeMA_value($VMA50_5[i]) vma50_10 = VolumeMA_value($VMA50_10[i]) // 指標の計算に必要な日数を経過していない場合は何もしない if ! (ma3 && ma100 && ma100_5 && ma100_10) return end //================================================= //トレンド判定 //================================================= stpflg = 0 if 75 < Index stpflg = StockPosition(i) end // ここまで ======================================== if 1==PricedataExistCheck(Close) return end //================================================== // 保有してない→購入 //================================================== if (! $hold[i]) // 1) 移動平均100日が上向き // 2) 出来高移動平均50日が上向き if (ma100_10 < ma100_5 && ma100_5 < ma100 && vma50_10 < vma50_5 && vma50_5 < vma50) //================================================== // 売買(買い) //================================================== // 3) 終値が25日移動平均より大きい // 4) 移動平均3日がHL Band(3日)のLバンドより小さい if (Close > ma25 && $HLB[i][2] > ma3 && stpflg == 1) $long = 0 $long = Num($buyUnit,Close) $buyflag[i] = 1 end end //================================================== // 保有している→売却 //================================================== elsif $hold[i] //終値と5日移動平均線の乖離率を計算する r5 = 100*(Close - ma5)/ma5 if $set[i] < 1 $set[i] = 1 return end $set[i] = $set[i] + 1 //================================================== // 売買(売り) //================================================== // 1) 利食い:終値と移動平均(5日)との乖離率が0%以上 // 2) 利食い:含み益が10%を上回った if (r5 > 0 || Close >= 1.10 * $buy[i]) PrintLog("利食い") $sellflag[i] = 1 $set[i] = 0 // 3) 損切り:実働10日(≒カレンダーで14日)経過 elsif ($set[i] > $MaxHoldDay) $sellflag[i] = 1 $set[i] = 0 end end end //==================== // 売買関数 //==================== def BuySell(j) if PricedataExistCheck(Close) return end if $buyflag[j] $long = 0 $long = Num($buyUnit,Close) Buying(j) $buyflag[j] = 0 elsif $sellflag[j] Selling(j) $sellflag[j] = 0 end end //==================== // 銘柄コードを変えながらMain関数,BuySell関数を実行 //==================== i = -1 j = -1 while i + 1 < $code_num i = i + 1 {codes[i]}Main(i) end while j + 1 < $code_num j = j + 1 {codes[j]}BuySell(j) end // 最後に$cntを0に戻し次の日に進める $cnt=0 // PrintLog("=======>END ") |
バックテスト結果
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 |
株価データ: 日足 銘柄リスト: 日経225採用銘柄 1998/01/05~2019/06/19における成績です。 ---------------------------------------- 全トレード数 3512 勝ちトレード数(勝率) 2171(61.82%) 負けトレード数(負率) 1341(38.18%) 全トレード平均利率 0.71% 勝ちトレード平均利率 3.10% 負けトレード平均損率 -3.16% 勝ちトレード最大利率 61.29% 負けトレード最大損率 -36.60% 全トレード平均期間 5.73 勝ちトレード平均期間 4.28 負けトレード平均期間 8.08 ---------------------------------------- 必要資金 ¥37,993,500 最大ポジション(簿価) ¥54,800,900 最大ポジション(時価) ¥56,943,400 純利益 ¥22,656,100 勝ちトレード総利益 ¥60,428,300 負けトレード総損失 -¥37,772,200 全トレード平均利益 ¥6,451 勝ちトレード平均利益 ¥27,834 負けトレード平均損失 -¥28,167 勝ちトレード最大利益 ¥608,000 負けトレード最大損失 -¥328,000 プロフィットファクター 1.60 最大ドローダウン(簿価) -¥3,193,600 最大ドローダウン(時価) -¥4,646,500 ---------------------------------------- 現在進行中のトレード数 2 ---------------------------------------- 各毎の利益額 2000年 131 ¥622,100 2001年 120 ¥820,600 2002年 152 ¥1,366,200 2003年 278 ¥5,597,200 2004年 198 ¥1,154,400 2005年 371 ¥5,902,700 2006年 188 ¥121,300 2007年 133 ¥665,200 2008年 51 -¥715,400 2009年 176 ¥3,823,400 2010年 134 ¥81,300 2011年 130 ¥588,200 2012年 202 ¥1,724,800 2013年 374 ¥1,730,100 2014年 234 -¥1,039,200 2015年 136 ¥484,400 2016年 110 ¥88,600 2017年 240 ¥660,400 2018年 128 -¥950,400 2019年 26 -¥69,800 |
利益曲線は次の通り。
勝率61.82%、PFは1.6です。
まとめ
ある程度の単調増加を実現できました。
しかし、イザナミで実現している「勝率70.12% PF2.69」には及ばない結果です。
近年は利益の幅が減っています。これらが勝率、PFを下げた可能性がありますが、「期間安値移動平均」をProtra上で実現する必要がありそうです。
なお、今回「終値と移動平均(5日)との乖離率が0%以上」のルール追加により、勝率がアップしています。