TradingViewで検証:トリプル移動平均

Posted on December 31st, 2018Updated on September 19th, 2019
TradingViewで検証:トリプル移動平均

※ この記事は最終更新日から5年以上が経過しています。

どんな記事

この記事では、何となく「優位性を向上」してくれそうなこと(移動平均線を2本から3本にすることなど)が、「必ずしもそうなるとは限らない」ということの一例を、数字とともに解説します。

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

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

 このシステムは150日、250日、350日の3つの移動平均を用いる。売買は150日移動平均が250日移動平均とクロスしたときに行われ、より長い350日移動平均はトレンドフィルターとして使われる。
短い2つの移動平均が長い350日移動平均と時価に対して同じ側にあるときのみ、取引が生じる。どちらも350日移動平均より高ければ、買い持ちトレードが、どちらも低ければ売り持ちのみが可能だ。
ダブル移動平均システムと異なり、このシステムは、つねには市場にとどまらない。150日移動平均が250日移動平均とクロスして下に抜ければ、取引は手じまいとなる。

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

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

ストラテジーを作成

TradingViewストラテジー トリプル移動平均線システム

エントリーとイグジット

買いエントリー

  • 「EMA150 と EMA250 が EMA350 より上に位置」「EMA150 と EMA250 のゴールデンクロス(上抜け)」で買いエントリー
  • 「EMA150 と EMA250 のデッドクロス(下抜け)」で決済
※ EMA●●:●●日指数平滑移動平均
TradingViewストラテジー トリプル移動平均システム 買いシグナルとイグジット

売りエントリー

  • 「EMA150 と EMA250 が EMA350 より下に位置」「EMA150 と EMA250 のデッドクロス(下抜け)」で売りエントリー
  • 「EMA150 と 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-sEMA-mEMA-lPyramiding
150250350None

テスト1 結果

損益最大DD取引数勝数勝率RR比
Total1827641.76%2.044
USDJPY34.9513.957342.863.350
EURJPY33.832.315480.003.906
GBPJPY141.890.0044100.00-
CHFJPY-2.9120.038337.501.478
CADJPY22.428.716583.330.715
NKY7414.473618.146350.002.444
DJI4457.573498.325360.001.516
DAX2146.543958.668450.001.399
UKX-350.802079.709555.560.692
HSI-33.598738.957228.572.490
6098-181.50181.50100.00-
44522662.00801.006350.003.390
5711-855.003275.0010220.003.222
7201-426.30878.3012433.331.152
99841826.001405.0010440.002.458
AAPL20.6418.806350.001.461
AXP58.040.0044100.00-
BA50.9825.056350.002.242
JNJ-17.8855.3314214.294.463
MCD38.817.565240.006.997
GOLD90560.0031640.006350.003.862
PLATINUM-4425.0026475.006350.000.874
WTI-8130.0059510.0010220.003.501
CORN6975.006475.008337.502.595
SOY BEANS-75550.0075550.0013215.380.817

テスト1 統計

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

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

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

「期待値」は、悪くはないですが長期の手法にしては低めな印象です。取引回数が少なく「収益の見込み」もあまり良くないですね。

テスト2

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

テスト2 設定

EMA-sEMA-mEMA-lPyramiding
1502503501-ATR 上限4

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

テスト2 結果

損益最大DD取引数勝数勝率RR比
Total62227744.53%1.845
USDJPY154.2141.00221045.454.170
EURJPY81.2319.85201155.003.595
GBPJPY514.120.001616100.00-
CHFJPY-56.85105.0830723.331.869
CADJPY71.0315.20211676.191.629
NKY25819.0111524.95231252.172.120
DJI21681.437793.57161275.001.261
DAX18369.387587.00231669.571.330
UKX-2910.808199.90321753.130.622
HSI-13905.6846240.3528828.571.748
6098-621.50621.50300.00-
445211851.001622.00191157.894.267
5711-8765.0017415.0038821.052.186
7201-1966.203261.20411434.150.865
99844634.006863.00351234.292.598
AAPL50.69111.05231252.171.148
AXP217.090.001616100.00-
BA264.1254.52181266.672.160
JNJ-23.65178.5839820.513.440
MCD138.6345.7118844.444.700
GOLD368200.0072030.00191263.163.565
PLATINUM-37405.00109275.00211257.140.537
WTI-72050.00270280.0031825.812.132
CORN6187.5029787.50301240.001.667
SOY BEANS-219787.50219787.5040717.500.776
  • 「取引回数」 182 → 622
  • 「勝率」 41.76 → 44.53
  • 「RR比」 2.044 → 1.845

勝率アップ、RR比はダウン。しかし、取引回数が増えているので「収益の見込み」はまったく問題ないでしょう。『「破産の確率」がアップしないか』と、『「期待値」がダウンしないか』に注目です。

テスト2 統計

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

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

期待値=勝率×RR比1勝率\text{期待値} = \text{勝率} \times \text{RR比} - | 1 - \text{勝率}|
収益の見込み=期待値×取引回数\text{収益の見込み} = \text{期待値} \times \text{取引回数}
  • 「期待値」 0.271 → 0.267
  • 「見込み収益」 49.311 → 166.045

「破産の確率」は上昇せず、「期待値」もほとんど低下せず、「見込み収益」は大幅アップ。手法を改善する施策としては完璧です。あとは「ドローダウン」とか「コンスタントに安定して収益を上げられるか」とかを確かめる必要がありますが、TradingViewではちょっとむずかしいかもしれないですね。

考察

移動平均線を2本から3本に増やすことは、何となく「優位性を向上」してくれそうな気がしますが、「必ずしもそうとは限らない」ということですね。

このことは、言われてみれば誰しも「そりゃあそうだ」と思うことですが、そういう人に限って「わりとやりがち」なことだと思います。優位性を向上させるつもりが、逆効果になってしまうんですね。

  1. イメージだけで実践してしまう
  2. 検証のサンプルが少ない(銘柄、期間、足種など)
  3. そもそも優位性についての理解が足りない

こういうことがあると、逆効果になります。

「2」についてはいくつかアプローチがあって、特定の銘柄のクセに合わせて組み立てるとしたらサンプルを限定しても良いケースもあります。いずれにしても過剰な最適化には注意が必要だと思います。

Pineスクリプト

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

Pineスクリプト

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



src = close
S        = input(150  ,minval=1 ,title="short_")
M        = input(250  ,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)

S_ = ema(close ,S)
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 = S_ >= M_ and S_ >= L_ and M_ >= L_
S_EntrySig = S_ <= M_ and S_ <= L_ and S_ <= 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_ <= M_ and strategy.position_size > 0
  S_ExitSig = S_ >= M_ 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)
plot(S_ ,color=red     ,title="短期EMA" ,style=line ,linewidth=2, transp=0)

TradingViewでも公開しています!

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

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

バックテストならTradingView

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

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

行うことができます。

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

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

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

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

yuya takahashi

タカハシ / 11年目の兼業投資家

投資やプログラミング、動画コンテンツの撮影・制作・編集などが得意。更新のお知らせは、LINE、メールで行っています。

このブログと筆者についてご質問はこちら

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