TradingViewで検証:ダブル移動平均

Posted on December 26th, 2018Updated on May 4th, 2019
TradingViewで検証:ダブル移動平均

どんな記事

ありきたりな移動平均線のゴールデンクロスとデットクロスを使った手法でも、長期で運用すると(統計的には)利益がでます。この記事では、その結論にいたる〝バックテストの結果〟をご紹介 します。

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

まずは、「ダブル移動平均」について書かれている箇所を、書籍「伝説のトレーダー集団 タートルズ流投資の魔術」から引用します。

 100日移動平均が、それより動きの遅い350日移動平均とクロスして上に抜いたときに売買を行うという非常に単純なシステムだ。他のシステムと異なり、このシステムは、買い持ち売り持ちにかかわらず、つねに市場にあらわれる。唯一の退出時は、動きの速いほうの移動平均が遅いほうの移動平均とクロスして下に抜いたときで、この時点で手じまいし、逆方向に新しい取引を仕掛けることになる。
(中略)
おそらくおわかりだろうが、このシステムは非常に長期のトレンドフォロー・システムで、他の大半のシステムのように頻繁にトレードが行われるわけではない。

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

「このシステムは、買い持ち売り持ちにかかわらず、つねに市場にあらわれる

つまり、常に「何かしらのポジションを保有するシステム」であるということです。この記事は、上記の手法を TradingView で再現することを目的としたものです。

ストラテジーを作成

TradingViewストラテジー ダブル移動平均線システム

エントリーとイグジット

非常にシンプルなスキームです。ゴールデンクロスとデットクロスで途転どてん(決済して反対の方向のエントリー)して常に市場にポジションを保有し続けます。

買いエントリー

  • 「EMA100 と EMA350 のゴールデンクロス(上抜け)」で買いエントリー
  • 「EMA100 と EMA350 のデッドクロス(下抜け)」で決済

※ EMA●●:●●日指数平滑移動平均

TradingViewストラテジー ダブル移動平均システム 買いシグナルとイグジット

売りエントリー

  • 「EMA100 と EMA350 のデッドクロス(下抜け)」で売りエントリー
  • 「EMA100 と EMA350 のゴールデンクロス(上抜け)」で決済

TradingViewストラテジー ダブル移動平均システム 売りシグナルとイグジット

バックテスト

同じ条件で手法を比べるために、以下の「基本条件」でテストしていきます。

バックテストの基本条件

期間

  • 2005年1月1日 ~ 2017年12月31日(12年間)

資金管理

  • 単利

銘柄

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

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

テスト1

まずは、本に掲載されていたものと同じ設定でバックテストをしてみます。

テスト1 設定

EMA-mEMA-lPyramiding
100350None

テスト1 結果

損益最大DD取引数勝数勝率RR比
Total2268537.612.977
USDJPY41.3415.348337.504.385
EURJPY49.4013.2510440.006.943
GBPJPY153.824.685480.008.474
CHFJPY9.7115.3111436.362.603
CADJPY13.429.427571.430.713
NKY7866.503678.938337.503.779
DJI4054.134339.958337.502.869
DAX4927.091897.559444.443.318
UKX286.501842.609555.560.908
HSI4145.364376.547342.862.596
6098-171.50171.50100.00-
44522072.00973.008337.503.813
5711-2560.004980.0013323.081.644
7201-604.50984.5015426.671.423
99843873.001417.009555.562.217
AAPL39.7217.666350.002.077
AXP63.670.0044100.00-
BA55.6924.896350.002.339
JNJ-13.1151.6913215.384.348
MCD45.2610.8512541.675.900
GOLD92450.0033150.007342.864.120
PLATINUM3530.0017745.007342.861.459
WTI-30520.0065700.0015320.002.569
CORN-1587.5011587.5011327.272.496
SOY BEANS-105862.50105862.5017317.650.732

※「勝ち保有」「負け保有」は、保有期間(日)の平均。※ RR比はGBPJPYと6098、AXPを除いた数値。

結果の良し悪しの差が激しいですね。大きく長期のトレンドが発生すると、かなり良い成績になるようです。

  • 「勝率」も「RR比」も、わりと良い
  • 保有期間が長い(4年近いものも)
  • 取引回数はボリンジャーの方が少なかった

テスト1 統計

破産の確率期待値/リスク収益の見込み
0.00%0.496112.064

破産の確率は、損失の許容=2%で算出しています。期待値と収益の見込みは以下の計算式で算出しています。

期待値=勝率×RR比1勝率\text{期待値} = \text{勝率} \times \text{RR比} - | 1 - \text{勝率}|
収益の見込み=期待値×取引回数\text{収益の見込み} = \text{期待値} \times \text{取引回数}

期待値も6098とAXPのRR比が含まれていないことに注意が必要ですが、おおむね良い数値であることには間違いなさそうです。ただの移動平均のクロスですが、超長期で用いるとわりと優秀な手法であることがわかります。

短期で用いた場合はさておき、超長期の移動平均の手法は有効そうです。

テスト2

次に、ピラミッティングを試してみます。

テスト2 設定

EMA-mEMA-lPyramiding
1003501-ATR 上限4

初回を含めて、4回エントリーします。

テスト2 結果

損益最大DD取引数勝数勝率RR比
Total72830341.62%2.340
USDJPY185.7245.90241145.834.477
EURJPY162.1835.78281657.143.544
GBPJPY566.6027.47201680.005.407
CHFJPY-1.8582.7836925.002.946
CADJPY31.4838.78251456.001.210
NKY28636.4013861.20281242.862.981
DJI24690.4110433.16201260.002.072
DAX15342.128051.42321650.002.119
UKX-160.406821.70301756.670.748
HSI-1763.4032369.11281035.711.703
6098-591.50591.50400.00-
445210964.001255.00221254.554.204
5711-9635.0017335.0040922.501.540
7201-2599.404017.40481327.081.217
998412229.005325.00332060.611.528
AAPL134.0681.18221254.551.537
AXP225.010.001616100.00-
BA166.51138.68221254.551.580
JNJ-24.16190.2241819.513.653
MCD179.6620.20251352.005.224
GOLD388110.00103960.00221254.553.645
PLATINUM-6890.0089870.00241250.000.953
WTI-144590.00286560.0045920.002.320
CORN-26737.5052500.00401230.001.742
SOY BEANS-331950.00331950.00531018.870.666
  • 「取引回数」 226 → 728
  • 「勝率」 37.61% → 41.62%
  • 「RR比」 2.977 → 2.340

勝率が改善したものの、RR比は悪化。期待値にしてみないとわからないですね。

テスト2 統計

破産の確率期待値/リスク収益の見込み
0.00%0.390284.052

破産の確率は、損失の許容=2%で算出しています。期待値と収益の見込みは以下の計算式で算出しています。

期待値=勝率×RR比1勝率\text{期待値} = \text{勝率} \times \text{RR比} - | 1 - \text{勝率}|
収益の見込み=期待値×取引回数\text{収益の見込み} = \text{期待値} \times \text{取引回数}
  • 「期待値」 0.496 → 0.390
  • 「見込み収益」 112.064 → 284.052

期待値としては悪化しましたが、取引回数が増加しているため「見込み収益」は大きく改善。ピラミッティングは良い施策であると言えそうです。これで破産の確率が上昇していたら問題ですが、それもなし。

テスト3

さて、最後に EMA の期間をかえて試してみたいと思います。

テスト3 設定

EMA-mEMA-lPyramiding
50350None

EMA100 を「50」に。ピラミッティングも「None」にします。

テスト3 結果

損益最大DD取引数勝数勝率RR比
Total3159128.89%3.361
USDJPY28.4523.1512325.005.249
EURJPY46.0719.0813646.152.358
GBPJPY170.2210.859444.4412.471
CHFJPY11.7021.7715426.673.498
CADJPY12.4229.8915426.673.433
NKY8839.935606.5410330.005.220
DJI1870.674827.9810440.001.902
DAX1770.713561.4711436.362.263
UKX-961.902739.3013430.771.594
HSI6376.266779.1913430.774.353
6098-105.00105.00100.00-
44521806.001501.0012325.004.982
5711-440.003740.0017317.654.251
7201-1097.001403.0029413.792.587
99841277.002587.0015533.332.526
AAPL50.7916.156350.002.783
AXP84.01-44100.00-
BA71.0220.436466.671.581
JNJ-9.4450.2519315.794.529
MCD30.5310.858337.504.196
GOLD103450.0017030.007457.143.145
PLATINUM20530.0023090.0010440.002.464
WTI-42390.0091150.0020420.002.448
CORN-1175.009100.0017317.654.473
SOY BEANS-86150.0086350.0023417.391.263
  • 「取引回数」 226 → 315
  • 「勝率」 37.61% → 28.89%
  • 「RR比」 2.977 → 3.361

今度は、勝率が悪化して、RR比が改善。「期待値」を算出してみます。

テスト3統計

破産の確率期待値/リスク収益の見込み
0.07%0.26081.835

破産の確率は、損失の許容=2%で算出しています。期待値と収益の見込みは以下の計算式で算出しています。

期待値=勝率×RR比1勝率\text{期待値} = \text{勝率} \times \text{RR比} - | 1 - \text{勝率}|
収益の見込み=期待値×取引回数\text{収益の見込み} = \text{期待値} \times \text{取引回数}

期待値と見込み収益ともに大きく悪化。取引回数が増えたもののカバーできず。破産の確率も、まだ問題のない範囲ではありますが悪化しています。やはり勝率とRR比だけではなかなか判断がつかないですね。

考察

  • コモディティは超長期の手法に向いていないのかもしれない
  • 超長期で EMA のクロスがワークするのは、競合が少なく、価格操作が容易ではないためか

ここ最近、超長期のバックテストを行っていて、ふとこんなことを考えていました。

コモディティは超長期の手法に向いていない

これは、とくに「WTI、Corn、SoyBeans」あたりです。

このあたりのコモディティって、わりと「適正価格」というものがあって、そこから大きく乖離することが少ないです。例えば原油は今「数十ドル」ですが、この価値が半分や倍になるなんてことはあまり起きないわけです。「これはコモディティならではなのかな」なんて思います。

あとは、わりと日本株も負けがち。米株はよく勝てるのに。

超長期でEMAのクロスがワークするのは何故か

最初はとくに不思議には思わなかったのですが、よくよく考えてみると疑問をもちます。

なぜ、短期でワークしない EMA のクロスが長期では有効なのか――

いくつか思い当たる理由があります。
一つは、競合が少ないということです。

一般的によくトレードされる足種、日足とか4時間足、1時間足などは投資家がたくさんいます。投資家がたくさんいるということは、彼らをだまそうとする動きも多くでてくるはずです。

今回は行っていませんが、1980年あたりの価格でバックテストすると単純なブレイクアウトの手法が非常に有効だったりします。しかし、ここ最近では優位性が大きく損なわれています。何が原因なのか明確にはわかりませんが、投資家が多い時間軸において、そういう 〝だまし〟のような値動きが多い ことは間違いないと思います。

もう一つは、価格操作が容易ではないということです。

超長期の価格を操作しようと考えたときに、膨大な資金力がないとなし得ないことは簡単に想像ができます。例えファンドであっても、長期間にわたって価格に影響をあたえ続けることは困難です。ファンドの影響の少ない安全圏であるのではないかと考えています。

とはいえ、超長期の手法は「すぐに結果がでない」「損失を長く放置しなくてはいけない」など、ハードルが非常に高いです。だからこそ競合が少ないのだと思います。

(筆者は実践してみていますが、)安易にできる手法ではないので、導入する際には注意が必要です。

Pineスクリプト

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

Pineスクリプト

 strategy("Strategy Turtle Double EMA"
   ,default_qty_type=strategy.fixed
   ,default_qty_value=1
   ,pyramiding=4
   ,overlay=true)



 src = close
 M        = input(50   ,minval=1 ,title="middle_")
 L        = input(350  ,minval=1 ,title="long_")   
 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(1    ,type=float ,minval=0.5 ,title="pyramiding ATR*N")
 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)

 M_ = ema(close ,M)
 L_ = ema(close ,L)

 atr_LO_ = ema(tr ,LO_len)
 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]



 L_EntrySig = M_ >= L_
 S_EntrySig = M_ <= L_
 lo_sig2    = strategy.position_size>0 ? lo2 < high : strategy.position_size<0 ? lo2 > low : na
 lo_sig3    = strategy.position_size>0 ? lo3 < high : strategy.position_size<0 ? lo3 > low : na
 lo_sig4    = strategy.position_size>0 ? lo4 < high : strategy.position_size<0 ? lo4 > low : na



 if(strategy.position_size != 0)

     L_ExitSig = S_EntrySig and strategy.position_size > 0
     S_ExitSig = L_EntrySig and strategy.position_size < 0

     strategy.close_all(when = L_ExitSig or S_ExitSig)

     if(L_ExitSig or S_ExitSig)
         entry1  := na
         entry2  := na
         entry3  := na
         entry4  := na
         lo2     := na
         lo3     := na
         lo4     := na



 if(strategy.position_size > 0)

     if(lo_sig2 and MAX_N >= 2)
         lo2 := na
         strategy.entry("L-Entry2" ,strategy.long ,comment="L-Entry2")
     if(lo_sig3 and MAX_N >= 3)
         lo3 := na
         strategy.entry("L-Entry3" ,strategy.long ,comment="L-Entry3")
     if(lo_sig4 and MAX_N >= 4)
         lo4 := na
         strategy.entry("L-Entry4" ,strategy.long ,comment="L-Entry4")



 if(strategy.position_size < 0)

     if(lo_sig2 and MAX_N >= 2)
         lo2 := na
         strategy.entry("S-Entry2" ,strategy.short ,comment="S-Entry2")
     if(lo_sig3 and MAX_N >= 3)
         lo3 := na
         strategy.entry("S-Entry3" ,strategy.short ,comment="S-Entry3")
     if(lo_sig4 and MAX_N >= 4)
         lo4 := na
         strategy.entry("S-Entry4" ,strategy.short ,comment="S-Entry4")



 if((L_EntrySig or S_EntrySig) and isWork and strategy.position_size==0)
     countTradingDays := 0
     entry1           := close

     if(L_EntrySig)
         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

     if(S_EntrySig)    
         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


 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(atr_LO    ,transp=0 ,title="ATR_LO")



 plot(L_ ,color=#303F9F ,title="長期EMA" ,style=line ,linewidth=2, transp=0)
 plot(M_ ,color=#4CAF50 ,title="中期EMA" ,style=line ,linewidth=2, transp=0)

TradingViewでも公開しています!

TradingView で ストラテジー「Turtle Double EMA」を見つける

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

バックテストならTradingView

TradingViewのテストは大変便利で、

  • かなり自由の効くバックテストを
  • 短時間で簡単に、
  • 価格データを用意することなく
  • 豊富な銘柄と足種を対象に

行うことができます。

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

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

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

わりと、30分くらいあればインジケーターを作成することもできます。便利。

著者

タカハシ / 9年目の兼業トレーダー

元・日本料理の板前。現在は、投資やプログラミング、動画コンテンツの撮影・制作・編集などを。更新のお知らせは、各SNSやLINEで。LINEだと1対1でお話することもできます!

このブログと筆者について運用管理表

  • 記事をシェア
© Investment Tech Hack 2021.