25銘柄12年✕2→利益!ATRチャネル・ブレイクアウトをTradingViewで検証

25銘柄12年✕2→利益!ATRチャネル・ブレイクアウトをTradingViewで検証

この記事を読むと次のことができる(わかる)ようになります
・「投資の魔術」掲載の手法をTradingViewで再現
・誰でも "無料 & 5分" で同じバックテストができる(コードも無料公開)
・10年以上むかしの手法が "現在でも通用するのか" が分かる

2018年12月5日 修正
5. ストラテジーのPineスクリプト」のコードを一部修正しました
「,style=linebr」を追加
2018年12月8日 追記
「5-1. TradingViewでも公開しています!」を追加しました

10年以上も前に「利益が出る」と紹介された手法が、現在でも通用するのか

この記事は、2007年10月に出版された「伝説のトレーダー集団 タートルズ流投資の魔術」に掲載されている手法を、TradingViewで再現するものです。

  1. ATRチャネル・ブレイクアウト ◀ イマココ
  2. ボリンジャー・ブレイクアウト
  3. ドンチアン・トレンド・システム
  4. 時限退出付きドンチアン・トレンド
  5. ダブル移動平均
  6. トリプル移動平均

25銘柄12年→利益!
ATRチャネル・ブレイクアウトをTradingViewで検証

  1. タートルズ流 投資の魔術 からの引用
  2. ストラテジーを作成
    1. エントリーとイグジット
  3. バックテスト
    1. テスト1
    2. テスト2
  4. 考察
  5. ストラテジーのPineスクリプト
    1. TradingViewでも公開しています!
  6. バックテストならTradingView

1. タートルズ流 投資の魔術 からの引用

まずは、この記事の主題でもある「ATRチャネル・ブレイクアウト」について書かれている箇所を「伝説のトレーダー集団 タートルズ流投資の魔術」から引用します。

 ATRチャネル・ブレイクアウト・システムは、変動性の尺度として真の値幅の平均(ATR)を使用するものだ。チャネルは、350日の終値の移動平均にATRの7倍を加えたものを上限とし、ATRの3倍を引いたものを下限として形成される。前日の終値がチャネルの最高値を超えていたら寄り付きから買い持ちのトレードが仕掛けられ、前日の終値がチャネルの最安値より下回れば、売り持ちとなる。価格が戻して終値が移動平均とクロスしたら、取引は手じまいだ。

 ATRチャネル・ブレイクアウト・システムのバリエーションのひとつは、PGO(プリティー・グッド・オシレーター)システムという名称で、チャック・ルボーズ・システムトレーダーズ・クラブ(www.traderclub.com)フォーラムのトレーダー、マーク・ジョンソンが普及させた。これは次に述べるボリンジャー・ブレイクアウト・システムの変形でもある。

引用元
伝説のトレーダー集団 タートルズ流投資の魔術(P.165)

この記事は、上記の手法をTradingViewで再現することを目的としたものです。

目次へ

2. ストラテジーを作成

TradingView ATRチャネル・ブレイクアウト・ストラテジー

チャートが再現できているか確認するために、「伝説のトレーダー集団 タートルズ流投資の魔術」の P.166 図21 と同じものを作成してみました。

同じ期間と銘柄でチャートを出してみたものの、おそらく「つなぎ足と限月の違い」があり、まったく同じチャートにはなりませんでした。厳密には「同じ銘柄がなかった」と言うべきでしょうか。もしかしたら、「SMAとEMA」の違いもあるかもしれません。

ただ、近い形にはなっているため「大きな問題はないだろう」と判断しています。

パラメーターやコードは「5. ストラテジーのPineスクリプト」をご覧ください。

目次へ

2-1. エントリーとイグジット

買いエントリー

  • 「EMA350+ATR20の7倍」を終値で上抜けたら買いエントリー
  • 買い持ちの状態で「EMA350」を終値で下抜けたら決済

※ EMA350:350日指数平滑移動平均、ATR20:20日ATR

※ ATRがわからない方はこちらの記事をお読みください

TradingView ATRチャネル・ブレイクアウト・ストラテジー 買いシグナルとイグジット

売りエントリー

  • 「EMA350-ATR20の3倍」を終値で下抜けたら売りエントリー
  • 売り持ちの状態で「EMA350」を終値で上抜けたら決済

※ EMA350:350日指数平滑移動平均、ATR20:20日ATR

※ ATRがわからない方はこちらの記事をお読みください

TradingView ATRチャネル・ブレイクアウト・ストラテジー 売りシグナルとイグジット

サンプルとして、きっちり獲れてる場面を掲載していますが、割と獲れない場面の方が多いです。ただ、獲れるときは、獲れないときの何倍も獲れる。「The トレンドフォロー」ですね。

目次へ

3. バックテスト

つくったストラテジーで実際にテストをしてみました。
同じ条件で手法を比べるために、このシリーズでは以下の「基本条件」でテストしていくこととします。

バックテストの基本条件

  • 期間

    • 2005年1月1日 ~ 2017年12月31日
    • 12年間
  • 銘柄

    • 為替(5):
      USDJPY、EURJPY、GBPJPY、CHFJPY、CADJPY
    • 株価指数(5):
      UKY日経225、DJI NYダウ、DAXドイツ、UKXイギリスFTSE、HSI香港ハンセン
    • 日本株(5):
      6098リクルート、4452花王、5711三菱マテリアル、7201日産、9984ソフトバンクグループ
    • 米株(5):
      AAPLアップル、AXPアメリカン・エクスプレス、BAボーイング、JNJジョンソン・エンド・ジョンソン、MCDマクドナルド
    • 海外商品(5):
      金、白金、原油、コーン、大豆
  • その他

    • 資金管理:単利

手法は、市場との相性があるケースも多いので、主要な各市場から5銘柄ずつピックアップしてテストします。

TradingView のバックテストの資金管理は単利で検証するのが良いと思います。実戦向きな設定がないので。

目次へ

3-1. テスト1

まずは、「本に掲載されていたものと同じ」テストを行います。あくまでも、本から読み取れる情報をもとに「こうだろうな」と設定したものです。

テスト1設定

MA ATR Upper Lower Losscut Pyramiding
350 20 7 3 None None

テスト1結果

  損益 最大DD 取引数 勝数 勝率 RR比 勝ち保有 負け保有
TOTAL     383 113 29.50 4.090    
USDJPY 23.80 23.14 15 5 33.33 3.441 421 42
EURJPY 38.13 17.03 16 8 50.00 1.978 289 34
GBPJPY 162.40 8.92 9 5 55.56 7.959 519 36
CHFJPY 8.12 22.97 15 3 20.00 4.954 380 70
CADJPY -2.05 19.53 17 5 29.41 2.288 295 53
NKY 8494.24 6386.40 19 5 26.32 5.364 403 60
DJI 9202.67 1345.76 13 5 34.46 5.095 368 73
DAX 1688.00 3206.79 16 6 37.50 1.946 374 53
UKX -431.40 3254.80 17 4 23.53 3.108 375 73
HSI 2072.38 16969.29 18 5 27.78 3.057 316 57
6098 1179.50 80.00 2 1 50.00 15.744 494 39
4452 794.00 1647.00 18 4 22.22 4.323 383 53
5711 -1095.00 3425.00 20 6 25.00 2.377 272 68
7201 -2113.20 2113.20 30 1 3.33 5.230 393 51
9984 2703.00 2070.00 16 6 27.50 3.018 315 50
AAPL 76.65 30.10 12 5 41.67 3.747 482 80
BA 186.10 39.07 12 5 41.67 5.994 421 61
AXP 73.63 7.64 9 5 41.67 5.994 421 61
JNJ 1.49 40.79 18 3 16.67 5.925 349 63
MCD 57.96 22.34 12 4 33.33 5.720 414 83
GOLD 88610 19470 8 4 50.00 3.056 587 59
PLATINUM 36915 16315 15 5 33.33 5.796 355 74
WTI 110 61140 19 5 26.32 3.265 264 37
CORN 3287.5 9750 16 4 25.00 3.948 306 98
SOY BEANS -6425 30412 21 4 19.05 4.026 320 55

※ 「勝ち保有」「負け保有」は、保有期間(日)の平均

25銘柄12年間のテスト。サンプル数は383トレードと少し心もとないですね。

破産の確率はゼロ。おおむねほとんどの銘柄で損益プラスの成績。日本株が、他の市場と比べると不向きかもしれません。

TradingViewのバックテストには、残念ながら「年ごとの統計をとる機能」がないため詳細がわからないのですが、ものの数十分でイチからこれだけのテストができるのは非常に優秀だと思います。

テスト1統計

破産の確率 0%
期待値/リスク 0.5

※ 破産の確率は、損失の許容=2%で算出

※ 期待値/リスク = 勝率 ✕ RR比 -|1- 勝率|

簡易的に計算した期待値ですが、プラスになりました。

目次へ

3-2. テスト2

次に、ピラミッティングのギミックを追加して "すこし攻撃的な手法" にしてみます。

テスト2設定

MA ATR Upper Lower Losscut Pyramiding
350 20 7 3 None 10-ATR 上限4

今回加えたピラミッティングは、「エントリーした価格からプラス方向にATRの10倍動いたらポジションを追加する」というものです。それを3回行い、プラス方向に大きく値段が動いた場合、最初のエントリーを含めて「4になる」ということです。「ボクはそう表現している」ということですね。

テスト2結果

  損益 最大DD 取引数 勝数 勝率 RR比 勝ち保有 負け保有
TOTAL     591 235 39.76 3.100    
USDJPY 72.78 32.87 20 8 40.00 3.710 540 72
EURJPY -3.18 32.21 27 10 37.04 1.644 309 95
GBPJPY 327.20 25.43 21 14 66.67 3.689 517 83
CHFJPY 15.12 48.63 22 6 27.27 3.296 458 73
CADJPY -56.29 64.30 28 9 32.14 0.983 283 86
NKY 27987.02 10273.46 29 12 41.38 4.917 371 82
DJI 16318.82 6114.77 26 13 50.00 2.823 315 98
DAX 6360.26 3557.44 25 12 48.00 2.087 393 87
UKX -368.50 5365.40 25 9 36 2.199 361 77
HSI 5674.91 39666.1 18 5 27.78 3.057 316 57
6098 4095 80 5 4 80.00 13.047 207 39
4452 8769 1793 25 9 37.50 5.522 373 57
5711 -3155 8070 29 10 34.48 1.338 240 87
7201 -3057 3057 35 2 5.71 2.597 365 57
9984 2802 4654 27 10 37.04 2.264 305 57
AAPL 252.59 59.72 26 15 57.69 3.034 395 120
AXP 109.16 14,78 17 11 64.71 2.222 368 141
BA 510.62 46.68 24 14 58.33 4.417 357 93
JNJ 48.62 41.33 23 7 30.43 4.188 373 67
MCD 135.3 32.16 21 11 52.38 3.568 321 103
GOLD 259110 19470 15 11 73.33 2.666 552 59
PLATINUM 36540 41000 26 11 42.31 2.078 295 97
WTI -5630 91700 27 8 29.63 2.285 287 69
CORN -22600 33025 23 6 26.09 1.449 321 107
SOY BEANS 16112.5 54475 27 8 29.63 2.875 324 59

※ 「勝ち保有」「負け保有」は、保有期間(日)の平均

TOTALの勝率が「29.5% → 39.76%」と向上。一方でRR比は「4.09 → 3.1」と悪い数値に。これらは、2つの "バランス" が大切で、この "バランス" を「破産の確率」や「期待値」として表現することができます。

テスト2統計

破産の確率 0%
期待値/リスク 0.63

※ 破産の確率は、損失の許容=2%で算出

※ 期待値/リスク = 勝率 ✕ RR比 -|1- 勝率|

テスト1と比較すると、期待値「0.5 → 0.63」と向上。破産の確率の悪化も見られないため、ピラミッティングを導入することによって「成績の向上が期待できそう」だということが言えそうです。

目次へ

4. 考察

ふたつのテストをそれぞれ "25銘柄・12年" で行いました。長期の手法であるためサンプル数(トレードの回数)は少し物足りないですが、サンプルの "質" は十分であると考えています。

今回テストを行った「ATRチャネル・ブレイクアウト」は10年以上も前に紹介されたものですが、「現在でも通用しそうだ」ということが言えそうですね。また、ピラミッティングの導入などで、まだまだ成績の向上も見込めそうです。

また、テスト結果から「どれくらいの利益を見込める手法なのか」を算出することもできます。(たぬきの皮算用

テスト2の結果

  • トレード回数:591回
  • 期待値:リスクに対して0.63倍

これに対して、以下の条件でトレードする

  • 元金100万円
  • 単利
  • 1トレードのリスクを2%(2万円)に

2万円 ✕ 0.63 ✕ 591トレード = 7,446,600円

単利で200万円を750万円弱にできた手法だということがわかります。もっとリアルな検証をする必要はありますが、"期間ごとの複利" を取り入れることでもっと大きな利益を狙うこともできそうです。

念のため補足しておくと、このバックテストは明確な損切りを設定しているものじゃないので、上記のようにリスクを固定することは少しむずかしいです。これも、"リアルなバックテスト" をしてみると、もうちょっと見えてくるポイントですね。

目次へ

5. ストラテジーのPineスクリプト

今回行ったバックテストに用いたストラテジーのコード(Pineスクリプト)を公開します。販売や二次配布以外は自由にご利用いただいて差し支えありません。ご自由にお使いください!

Pineスクリプト:Strategy Turtle ATR Chanel Break Out

//@version=3
 strategy("Strategy Turtle ATR Chanel Break Out"
   ,default_qty_type=strategy.fixed
   ,default_qty_value=1
   ,pyramiding=4
   ,overlay=true)
 
 src      = close
 len      = input(350  ,minval=1  ,title="ma length")
 atr_len  = input(20   ,minval=1  ,title="band atr length")
 up_n     = input(7    ,minval=1  ,title="atr upper length")
 low_n    = input(3    ,minval=1  ,title="atr lower length")
 SO_bool  = input(false,type=bool ,title="loss cut")
 SO_len   = input(20   ,type=integer ,minval=1 ,title="loss cut ATR length")
 SO_N     = input(2    ,type=float  ,minval=0.5 ,title="loss cut ATR*N")
 MAX_N    = input(1    ,type=integer ,minval=1 ,maxval=4 ,title="maximun num of unit")
 LO_len   = input(20   ,type=integer ,minval=1 ,title="pyramiding ATR length")
 LO_N     = input(10   ,type=float  ,minval=0.5 ,title="pyramiding ATR*N")
 Tm_bool  = input(false,type=bool  ,title="timed exit")
 Tm_len   = input(80   ,type=integer ,minval=1 ,title="timed exit length")
 fromYear = input(2005 ,type=integer ,minval=1900 ,title="test start")
 endYear  = input(2017 ,type=integer ,minval=1900 ,title="test end")
 
 isWork   = timestamp(fromYear ,1 ,1 ,00 ,00) <= time and time < timestamp(endYear+1 ,1 ,1 ,00 ,00) 
 
 EMA = ema(close ,len)
 ATR = ema(tr ,atr_len)
 UPPER = EMA + ATR * up_n
 LOWER = EMA - ATR * low_n
 
 atr_SO_ = ema(tr ,SO_len)
 atr_LO_ = ema(tr ,LO_len)
 atr_SO = atr_SO_*SO_N
 atr_LO = atr_LO_*LO_N
 
 countTradingDays     = na
 countNonTradingDays  = na
 countTradingDays    := strategy.position_size==0 ? 0 : countTradingDays[1] + 1 
 countNonTradingDays := strategy.position_size!=0 ? 0 : countNonTradingDays[1] + 1
 entry1   = close
 entry2   = close
 entry3   = close
 entry4   = close
 entry1  := strategy.position_size==0 ? na : entry1[1]
 entry2  := strategy.position_size==0 ? na : entry2[1]
 entry3  := strategy.position_size==0 ? na : entry3[1]
 entry4  := strategy.position_size==0 ? na : entry4[1]
 lo2      = close
 lo3      = close
 lo4      = close
 lo2     := strategy.position_size==0 ? na : lo2[1]
 lo3     := strategy.position_size==0 ? na : lo3[1]
 lo4     := strategy.position_size==0 ? na : lo4[1]
 losscut  = close
 losscut := strategy.position_size==0 or SO_bool==false ? na : losscut[1]
 
 
 
 L_EntrySig = close >= UPPER and isWork
 S_EntrySig = close <= LOWER and isWork
 
 
 
 if(strategy.position_size != 0)
     L_ExitSig = (close <= EMA or S_EntrySig) and strategy.position_size > 0
     S_ExitSig = (close >= EMA or L_EntrySig) and strategy.position_size < 0
 
     TimedSig  = countTradingDays > Tm_len and Tm_bool
     strategy.close_all(when = L_ExitSig or S_ExitSig or TimedSig or not isWork)
     
     if(L_ExitSig or S_ExitSig)
         entry1  := na
         entry2  := na
         entry3  := na
         entry4  := na
         lo2     := na
         lo3     := na
         lo4     := na
         losscut := na
     
 if(strategy.position_size > 0)
     lo_sig2 = lo2 < high
     lo_sig3 = lo3 < high
     lo_sig4 = lo4 < high
     
     if(lo_sig2 and MAX_N >= 2)
         if(SO_bool)
             strategy.entry("L-Entry2" ,strategy.long ,stop=close-atr_SO ,comment="L-Entry2")
             strategy.exit("L-Entry1"  ,stop=close-atr_SO)
         else
             strategy.entry("L-Entry2" ,strategy.long ,comment="L-Entry2")
         lo2     := na
         losscut := SO_bool ? close - atr_SO : na
     if(lo_sig3 and MAX_N >= 3)
         if(SO_bool)
             strategy.entry("L-Entry3" ,strategy.long ,stop=close-atr_SO ,comment="L-Entry3")
             strategy.exit("L-Entry2"  ,stop=close-atr_SO)
             strategy.exit("L-Entry1"  ,stop=close-atr_SO)
         else
             strategy.entry("L-Entry3" ,strategy.long ,comment="L-Entry3")
         lo3     := na
         losscut := SO_bool ? close - atr_SO : na
     if(lo_sig4 and MAX_N >= 4)
         if(SO_bool)
             strategy.entry("L-Entry4" ,strategy.long ,stop=close-atr_SO ,comment="L-Entry4")
             strategy.exit("L-Entry3"  ,stop=close-atr_SO)
             strategy.exit("L-Entry2"  ,stop=close-atr_SO)
             strategy.exit("L-Entry1"  ,stop=close-atr_SO)
         else
             strategy.entry("L-Entry4" ,strategy.long ,comment="L-Entry4")
         lo4     := na
         losscut := SO_bool ? close - atr_SO : na
 
 if(strategy.position_size < 0)
     lo_sig2 = lo2 > low
     lo_sig3 = lo3 > low
     lo_sig4 = lo4 > low
     
     if(lo_sig2 and MAX_N >= 2)
         if(SO_bool)
             strategy.entry("S-Entry2" ,strategy.short ,stop=close+atr_SO ,comment="S-Entry2")
             strategy.exit("S-Entry1"  ,stop=close+atr_SO)
         else
             strategy.entry("S-Entry2" ,strategy.short ,comment="S-Entry2")
         lo2     := na
         losscut := SO_bool ? close + atr_SO : na
     if(lo_sig3 and MAX_N >= 3)
         if(SO_bool)
             strategy.entry("S-Entry3" ,strategy.short ,stop=close+atr_SO ,comment="S-Entry3")
             strategy.exit("S-Entry2"  ,stop=close+atr_SO)
             strategy.exit("S-Entry1"  ,stop=close+atr_SO)
         else
             strategy.entry("S-Entry3" ,strategy.short ,comment="S-Entry3")
         lo3     := na
         losscut := SO_bool ? close + atr_SO : na
     if(lo_sig4 and MAX_N >= 4)
         if(SO_bool)
             strategy.entry("S-Entry4" ,strategy.short ,stop=close+atr_SO ,comment="S-Entry4")
             strategy.exit("S-Entry3"  ,stop=close+atr_SO)
             strategy.exit("S-Entry2"  ,stop=close+atr_SO)
             strategy.exit("S-Entry1"  ,stop=close+atr_SO)
         else
             strategy.entry("S-Entry4" ,strategy.short ,comment="S-Entry4")
         lo4     := na
         losscut := SO_bool ? close + atr_SO : na
 
 
 
 if((L_EntrySig or S_EntrySig) and strategy.position_size==0)
     countTradingDays := 0
     entry1           := close
     
     if(L_EntrySig)
         if(SO_bool)
             strategy.entry("L-Entry1" ,strategy.long ,stop=close-atr_SO ,comment="L-Entry1")
         else
             strategy.entry("L-Entry1" ,strategy.long ,comment="L-Entry1")
         lo2     := MAX_N >= 2 ? close + atr_LO     : na
         lo3     := MAX_N >= 3 ? close + atr_LO * 2 : na
         lo4     := MAX_N >= 4 ? close + atr_LO * 3 : na
         losscut := SO_bool ? close - atr_SO : na
 
     if(S_EntrySig)    
         if(SO_bool)
             strategy.entry("S-Entry1" ,strategy.short ,stop=close+atr_SO ,comment="S-Entry1")
         else
             strategy.entry("S-Entry1" ,strategy.short ,comment="S-Entry1")
         lo2     := MAX_N >= 2 ? close - atr_LO     : na
         lo3     := MAX_N >= 3 ? close - atr_LO * 2 : na
         lo4     := MAX_N >= 4 ? close - atr_LO * 3 : na
         losscut := SO_bool ? close + atr_SO : na
     
     
 plot(strategy.position_size ,transp=0 ,title="保有ポジションの数")
 plot(strategy.openprofit    ,transp=0 ,title="未決済の損益")
 plot(strategy.netprofit     ,transp=0 ,title="決済済みの損益")
 plot(strategy.closedtrades  ,transp=0 ,title="決済済み取引数")
 plot(countTradingDays       ,transp=0 ,title="取引日数")
 plot(countNonTradingDays    ,transp=0 ,title="ノンポジ日数")
 plot(entry1  ,title="entry1"  ,color=blue ,transp=0 ,style=linebr)
 plot(lo2     ,title="lo2"     ,color=red  ,transp=0 ,style=linebr)
 plot(lo3     ,title="lo3"     ,color=red  ,transp=0 ,style=linebr)
 plot(lo4     ,title="lo4"     ,color=red  ,transp=0 ,style=linebr)
 plot(losscut ,title="losscut" ,color=red  ,transp=0 ,style=linebr)
 plot(atr_SO  ,transp=0 ,title="ATR_SO")
 plot(atr_LO  ,transp=0 ,title="ATR_LO")
 // plot(strategy.max_drawdown  ,transp=50 ,title="最大DD")
 // plot(strategy.equity, title="equity", color=red, linewidth=2, style=areabr)
 
 p1 = plot(UPPER ,color=#303F9F ,title="UPPER" ,style=line ,linewidth=2, transp=0)
 p2 = plot(LOWER ,color=#4CAF50 ,title="LOWER" ,style=line ,linewidth=2, transp=0)
 plot(EMA ,color=red ,title="EMA" ,style=line ,linewidth=2 ,transp=0)
 fill(p1 ,p2 ,color=#2196F3 ,title="fill" ,transp=60)

5-1. TradingViewでも公開しています!

TradingView で ストラテジー「ATR chanel breakout」を見つける

TradingView のインジケーターの検索で「ATR chanel」と検索するとでてきます。上記のコードと同じストラテジーを使用することができます。

目次へ

6. バックテストならTradingView

TradingViewのバックテストは簡単

TradingViewのテストは大変便利で、かなり自由の効くバックテストを短時間で簡単に、価格データを用意することなく豊富な銘柄と足種を対象に行うことができます。

一方で、その簡便さと引き換えに、TradingViewではできないバックテストも多くあります。

たとえば「分散投資」や「資金管理」があげられますが、これらは投資において非常に重要な要素でもあり、これらを含めたバックテストをするならリアルさが不可欠です。こういったバックテストをするためには、やはりPythonなどのプログラミング言語で自作していくしかないと考えています。

とはいえ、TradingViewが便利であることは間違いなく、最近では、手法の検証はTradingViewで行い、良い手法が見つかったら更に詳細なテストをPythonで行うようにしています。できるものはTradingViewでサクサクやってしまいます。

ちなみに、機能的には無料アカウントで十分ですが、個別株の分析を行う際には有料アカウントが必要になります。

Back to Top

Investment Tech Hack

Sorry... doesn't support your browser

To get the best possible experience using our site we recommend that you upgrade to a modern web browser. Investment Tech Hackではご利用中のブラウザサポートはしていません。
Internet Explorerのアップグレード行う、もしくはその他のブラウザを使用しての閲覧をお願いします。