システム検証

前回は、指数を使わずに個別株価でシステムを評価すればパフォーマンスはマシになるのではないか?という仮定に対する検証を行い、確かにその通りのようだという結果を示しました。 今回も引き続き「高勝率システムの考え方と作り方と検証」の検証を行っていきます。

目次

実践

ルール

著書には次のようにあります。

1.トレード対象の銘柄は1株当たり5ドル以上で、200 日単純移動平均線を上回っていること。これによって、長期的な上昇トレンドであることが示される。

2.過去21 日(1カ月)での1日の平均出来高が少なくとも25 万株あること。これで、流動性がある銘柄であることが保証される。

3.100 日HV(ヒストリカルボラティリティ)の値が30 を超える(ヒストリカルボラティリティの定義については付録を参照のこと)。

4.10 日ADX(アベレージ・ディレクショナル・インデックス)の値が30 を超える(ADX の定義については付録を参照のこと)。

5.その銘柄が2日以上、続けて下げて引けていること。

6.今日、その銘柄はY期間移動平均線(Y=4、5、6)よりも少なくともX%(X=4%、5%、6%)下で引けること。この点については、具体例を見れば明らかになるだろう。

7.上のルールが満たされていれば、翌日に今日の終値よりもさらにZ%(Z=4~10%)下に指値を入れて買う。

8.3期間単純移動平均線を上回って引ける日に、終値で手仕舞う。

ローレンス・A・コナーズ他『高勝率システムの考え方と作り方と検証』(PanRolling、2014年)

前回もそうでしたが、場中や引けでのトレードが必要になるため、完全自動化を目指すのであればトレードシステムや、ブラウザの自動化などといったことが必要となります。今のところは手動でそういったことが出来るってことを前提にしておきます。

ストラテジーの構築

コードは下記のようになります。

class HvAdxPb < Strategy

    attr_accessor :closes, :z, :y, :x

    def initialize
      super
      @length = 201
      @t_price = nil
      @z = 0.04
      @y = 4
      @x = 0.04
    end

    def set_up
      super
    end

    def pass?
      super
    end

    def set_env
      super
      @t_price = nil
      if soks[-201..-1]
        @closes = Soks.parse(soks[-201..-2],:close)
        @open = soks[-1].open
        if soks[-1].low < soks[-2].close * (1-@z) and soks[-1].volume > @q / 3
          @t_price = (soks[-2].close * (1-@z)).to_i
        end
      end
    end

    def decide(env)
      if position.nil?
        return none if @t_price.nil?
      end
      if position
        ave = Soks.parse(soks[-3..-1], :close).ave(3)[-1]
        return none if ave > soks[-1].close
        return sell(soks[-1].close,@position.volume)
      else
        ave = closes.ave(200)[-1]
        return none if closes[-1] < ave

        hv = closes[-101..-1].log.dev(100)[-1] * Math.sqrt(365) * 100
        return none if hv < 30

        adx = soks[-25..-2].adx(10,14)[-1]
        return none if adx < 30

        diffs = closes[-3..-1].diff
        return none if not (diffs[-1] < 0 and diffs[-2] < 0)

        uave = closes[-@y..-1].ave(@y)[-1] * (1-@x)
        return none if closes[-1] > uave

        volume = calc_volume(@t_price,0.3)
        return buy(@t_price,volume)
      end
    end
  end
  • 終値 > 200日移動平均
  • ヒストリカルボラティリティ > 30
  • ADX > 30
  • 2日連続陰線
  • 4日移動平均からの乖離率 < -4%

だった場合に当日に前日比 -4%の位置で売買可能ならば買いを仕掛けます。つまり当日に取引があり、安値が前日比 -4%以下を満たしている場合となります。

チャートを書いて、確認をしておきます。

profit_histgram

問題なさそうですね。

ADXをRubyで実装したものが見当たらないので、ついでに紹介しておきます。このメソッドはArrayを継承しているクラスにあることを想定してます。

  def dx(length)
      result = []
      self.each_cons(length+1) do |values|
        pdm, mdm, tr = [], [], []
        values.each_cons(2) do |vs|
          pdm << vs[-1].high - vs[-2].high
          mdm << vs[-2].low - vs[-1].low
          if (pdm[-1] < 0 and mdm[-1] < 0) or pdm == mdm
            pdm[-1], mdm[-1] = 0, 0
          elsif pdm[-1] > mdm[-1]
            mdm[-1] = 0
          elsif pdm[-1] < mdm[-1]
            pdm[-1] = 0
          end
          tr << [vs[-1].high - vs[-1].low, vs[-1].high - vs[-2].close, vs[-2].close - vs[-1].low].max
        end
        ts, ps, ms = tr.sum, pdm.sum, mdm.sum
        pdi = ps / ts * 100
        mdi = ms / ts * 100
        result << (pdi - mdi).abs / (pdi + mdi) * 100
      end
      Soks[*result]
    end

    def adx(n,m)
      result = []
      self.dx(n).each_cons(m) do |dxs|
        result << dxs.sum / length
      end
      Soks[*result]
    end

検証

33業種別株価指数の構成銘柄66個を適当に選んでそれぞれのパフォーマンスを調べてみます。ほとんど取引は行われないため、取引がなかった銘柄については表示していません。期間は2007年から2017年とし、単利での結果です。

Code Income Trades Win PF Average DD
1720 20.92 4.0 100.0 0.0 5.23 0.0
2768 2.39 1.0 100.0 0.0 2.39 0.0
3048 -2.35 1.0 0.0 0.0 -2.35 -2.35
3103 6.56 1.0 100.0 0.0 6.56 0.0
3105 1.85 1.0 100.0 0.0 1.85 0.0
3110 -0.56 1.0 0.0 0.0 -0.56 -0.56
3436 2.96 1.0 100.0 0.0 2.96 0.0
3632 9.14 3.0 66.67 7.54 3.05 -1.4
3656 32.24 7.0 57.14 3.68 4.61 -10.34
4506 6.9 1.0 100.0 0.0 6.9 0.0
4902 -6.08 1.0 0.0 0.0 -6.08 -6.08
5411 1.19 1.0 100.0 0.0 1.19 0.0
5631 9.52 1.0 100.0 0.0 9.52 0.0
5901 -1.52 1.0 0.0 0.0 -1.52 -1.52
6101 29.6 2.0 100.0 0.0 14.8 0.0
7211 9.51 2.0 100.0 0.0 4.76 0.0
7832 8.58 2.0 100.0 0.0 4.29 0.0
8303 4.36 1.0 100.0 0.0 4.36 0.0
8306 3.82 1.0 100.0 0.0 3.82 0.0
8473 24.12 2.0 100.0 0.0 12.06 0.0
8515 -9.29 6.0 83.33 0.7 -1.55 -31.43
平均 2.3 0.6 76.5 0.2 1.2 -0.8
偏差 6.95 1.31 38.83 1.02 3.15 4.08

合計して40回程度しか取引をしていないので、これだけで判断はしきれませんが、勝率76%、平均1.2%とかなりパフォーマンスが高いことがわかります。

次に複利で対象銘柄を広げ、より実運用に近い形でバックテストを行ってみます。

対象銘柄はコードの若い順に並べて10個飛ばしに1つづピックアップし、初期資産は100万円とします。著書のルールにあった出来高も考慮することとします。

期間は2000年から2017年をもちいますが、200日の日足が必要になることから実際は2001年辺りからの取引となります。

結果は次のようになります。

======================================================
net income:               2912364.5999999973
profit | loss:            9023931.799999999    | -6111567.2
average:                  11511.322529644258
pf:                       1.5
max profit | max loss:    822393.0     | -526104.0
trades | wins | looses:   253     | 182     | 71
wins{%}                   71.9
max series of wins:       18
max series of looses:     6
average span{win}:        2
average span{loose}:      5
max drow down:            -1454140.8
======================================================

200回を超えるトレード回数であっても7割を超える勝率があるので、このシステムに対する信頼度は上がるのではないでしょうか?

次に損益曲線を見てみます。

profit_histgram

今年に入るまでかなり安定した成績であることが分かりますが、今年のドローダウンはちときついですね。

パフォーマンス悪化は、単に資金が増えたからってのでは説明しにくい減り方な気がします。

この本の発売は2014年ですので、手法が広まったことによるものなのかもしれません。

あるいは、このシステムは恐怖心からトレード機会が生まれるはずだという信念がもとになっているため、恐怖心に対する麻痺から、かなり下押してからでないとトレード機会が生まれにくくなっている、というような理由も考えられます。

まとめ

押し目を利用したシステムについて検証を行いました。かなり安定したシステムであることがわかりました。しかし、ここ最近パフォーマンスが悪化しているため、利用するにあたってはひとまずその原因究明が必要かもしれません。

ともあれ、何かと併用しながら運用するのに十分魅力的なシステムだと思います。

前回から「高勝率システムの考え方と作り方と検証」を読み始めています。

前回は窓を利用したシステムに対して33業種別株価指数を用いて検証を行い、優位はないことを確認しました。

しかし、個別の株価で確認を行うと案外優位はあるのでは?という可能性が見えてきました。そこで今回は個別株価を使ってギャップシステムを評価していこうと思います。

利用する銘柄は33業種別株価指数の構成銘柄より2つづつ選んだ66銘柄です。条件は出来高程度で、それなりに出来高があるものを適当にピックアップしました。

33業種別株価指数を用いていたのは、株式の分割併合に対する処理が未実装だったためです。まだ問題は残っていますが、まぁ良い感じになってきました。今まで作ってきたシステムも、あわせて検証してみたいと思います。

目次

実践

検証方法は33業種別株価指数を用いていた時の方法と変わりません。2007年から2017年の株価データを用いて、それぞれの銘柄でバックテストを行い、最後に結果を集計します。

長いですが、結果はこのようになります。

Code Income Trades Win PF Average DD
1322 64.22 193.0 61.14 1.31 0.33 -34.25
1379 29.69 163.0 60.74 1.22 0.18 -30.8
1515 66.98 196.0 59.69 1.23 0.34 -36.27
1605 -25.64 205.0 52.68 0.92 -0.13 -35.65
1720 106.82 188.0 63.3 1.4 0.57 -23.19
1721 71.76 187.0 62.03 1.34 0.38 -20.32
2264 83.51 171.0 63.16 1.5 0.49 -37.48
2269 74.07 120.0 67.5 1.81 0.62 -12.08
2331 53.13 184.0 66.85 1.28 0.29 -22.06
2379 26.77 186.0 60.22 1.06 0.14 -48.75
2768 15.89 167.0 58.08 1.06 0.1 -21.52
3048 -70.83 127.0 57.48 0.71 -0.56 -37.81
3092 145.0 169.0 60.36 1.57 0.86 -27.15
3101 29.67 129.0 55.04 1.18 0.23 -24.33
3103 66.83 68.0 57.35 2.0 0.98 -23.38
3105 1.28 207.0 61.84 1.0 0.01 -44.4
3110 -26.77 178.0 56.74 0.92 -0.15 -36.22
3231 19.3 205.0 59.02 1.06 0.09 -45.83
3407 50.82 192.0 58.85 1.26 0.26 -22.08
3436 -2.29 227.0 56.39 1.0 -0.01 -37.61
3632 28.95 164.0 58.54 1.11 0.18 -18.62
3656 -34.58 104.0 53.85 0.88 -0.33 -33.73
3861 31.41 161.0 62.73 1.16 0.2 -18.6
3863 -6.07 72.0 58.33 0.93 -0.08 -14.96
4021 76.13 200.0 59.0 1.33 0.38 -39.42
4503 72.45 186.0 66.67 1.47 0.39 -16.92
4506 48.7 168.0 64.29 1.25 0.29 -23.27
4543 93.06 203.0 67.49 1.43 0.46 -37.82
4902 40.4 221.0 65.16 1.12 0.18 -49.85
5002 1.36 199.0 58.29 1.0 0.01 -33.17
5017 -141.13 189.0 53.44 0.7 -0.75 -67.14
5105 -67.97 190.0 52.11 0.83 -0.36 -35.08
5110 103.96 207.0 62.8 1.41 0.5 -24.82
5202 -17.02 162.0 58.02 0.95 -0.11 -31.28
5411 -146.63 207.0 53.62 0.66 -0.71 -33.16
5413 -2.97 85.0 57.65 0.98 -0.03 -25.12
5631 -101.53 223.0 56.5 0.74 -0.46 -77.6
5802 19.43 225.0 59.11 1.07 0.09 -39.4
5803 39.09 202.0 60.4 1.13 0.19 -20.34
5901 115.97 209.0 67.94 1.5 0.55 -21.92
6101 -63.94 205.0 53.66 0.85 -0.31 -45.11
7181 6.22 24.0 62.5 1.19 0.26 -14.68
7203 0.55 229.0 59.83 1.0 0.0 -23.53
7211 -37.94 158.0 55.7 0.85 -0.24 -30.39
7701 113.89 223.0 67.26 1.52 0.51 -18.02
7832 75.75 188.0 63.83 1.38 0.4 -32.48
7867 -50.22 160.0 53.13 0.79 -0.31 -30.39
8001 -55.04 195.0 54.87 0.81 -0.28 -16.11
8253 11.05 206.0 57.28 1.03 0.05 -41.52
8303 31.03 154.0 58.44 1.11 0.2 -35.72
8306 -9.37 218.0 56.88 0.97 -0.04 -22.66
8473 -6.54 235.0 60.43 0.99 -0.03 -43.7
8515 -156.8 200.0 53.5 0.77 -0.78 -65.4
8601 5.92 217.0 56.22 1.02 0.03 -26.17
8750 6.1 153.0 58.17 1.03 0.04 -19.02
8801 92.39 224.0 60.71 1.3 0.41 -25.56
9001 5.28 150.0 53.33 1.04 0.04 -26.97
9006 63.97 161.0 66.46 1.56 0.4 -19.66
9101 -45.31 178.0 56.18 0.86 -0.25 -35.35
9107 -156.87 185.0 49.73 0.64 -0.85 -37.85
9201 64.43 78.0 69.23 2.18 0.83 -10.22
9202 -20.72 141.0 52.48 0.86 -0.15 -27.16
9302 -33.94 173.0 50.87 0.87 -0.2 -18.43
9303 47.71 200.0 55.5 1.21 0.24 -21.39
9504 -31.69 165.0 60.61 0.87 -0.19 -34.28
9531 84.41 174.0 64.37 1.57 0.49 -18.78
平均 13.2 176.3 59.2 1.1 0.1 -30.7
偏差 65.97 42.31 4.62 0.31 0.38 12.73

33業種別株価指数を用いてたときとは比べ物にならないですね。平均利益あと4倍は欲しいところですが。

ギャップを利用したシステムは、局所的なエッジに対して仕掛けるため、指数に平滑化してしまうと優位がなくなってしまっているのかもしれません。

SMA65CC3

SMA65CC3は65日の移動平均線を3日連続で上回っていたら仕掛けるシステムです。仕切りは仕掛けと一致するドテンシステムです。

長いとブログシステムに怒られたので、詳細をカットして平均と偏差のみ表示します。

Code Income Trades Win PF Average DD
平均 27.0 60.1 29.6 1.1 0.6 -59.4
偏差 140.76 14.63 5.89 0.47 2.65 22.77

こちらもバラつきはありますが、33業種別株価指数をもちいたときよりマシになっています。中には800%なんて利益を上げてる銘柄もありました。2379ディップ。定位からの上昇をつかむのはクロスシステムの醍醐味と行ったところでしょうか。

CB-PB

CB-PBは過去7日以内に20日高値をつけ、かつ3日以内に5日安値をつけていれば仕掛けるシステムです。仕切りのパターんがいくつかある中で、20日高値に戻ったら仕切るパターンをもちいています。

Code Income Trades Win PF Average DD
平均 -32.8 74.5 66.1 0.9 -0.4 -41.3
偏差 59.53 15.24 6.99 0.27 0.84 17.63

勝率の高さは相変わらずですが、これは使えませんね。

KAMA-PB

最後にKAMAをもちいたプルバックシステムです。これは自作のシステムで、33業種別株価指数をもちいた検証で十分に満足の行く結果が得られているものです。

また他にあれこれと検証を行った結果十分に実践投入が可能だろうと踏んでいるシステムです。

KAMAは指数平滑化平均の一種で、効率レシオによって平滑化の度合いが変動します。そのため上昇、下降局面で階段状のチャートを描く特徴があります。

このシステムは10日KAMA-STCが100または0かつ、KAMAの偏差0.5バンド以内で売買を仕掛け、仕切りはトレーリングストップを置きます。

Code Income Trades Win PF Average DD
平均 88.8 78.1 59.7 1.7 1.2 -30.4
偏差 79.26 16.61 6.33 0.63 1.11 11.96

個別銘柄でも申し分ない出来だと思います。バグが怖いですね。。。

まとめ

個別銘柄で検証を行うと、幾つかのシステムは33業種別株価指数による検証に対してパフォーマンスが上がっていることがわかりました。指数にすると銘柄ごとに発生したエッジが平滑化されて薄れている可能性があるのでしょう。

特にギャップを利用したシステムはこの傾向が強いと思われます。逆に、指数で良い結果の得られていたシステムは個別株価における検証でも十分な結果を示すことが確認できました。

著書にはこのシステムに対して、ギャップの下に指値で注文した時の効果や、RSI、平均などの効果について詳細な検証結果が示されていますが、ギャップを利用したシステム検証は一旦これで終わりにしたいと思います。

今回から「高勝率システムの考え方と作り方と検証」を読み進めていこうと思います。

先ずはじめに検証していくシステムはギャップ、窓開けを利用したものです。検証方法は今までと同様に33業種別株価指数を用いて行います。

目次

実践

ルール

著書のルールはこのようなものです。

1.私たちは2001 ~2012 年に取引されていた銘柄のうちで、1株5ドル以上で、過去21 取引日(1カ月)に少なくとも平均100 万株の出来高があるものをすべて調べた。こうするのは流動性がある銘柄だけを調べるためだ。

2.当日の2期間RSI の値が5以下で引ける。これで、その銘柄が売られ過ぎというシグナルになる(この水準を極端な売られ過ぎと見る人もいる)。RSI についてもっと知りたい人は、付録を参照してほしい。

3.翌日に、下にギャップを空けて寄り付けば(つまり、翌日の始値が今日の安値よりも安ければ)、寄り付きでその銘柄を買う。

4.あとの章ではいくつかの手仕舞いポイントを見ていくつもりだが、ここでの検証では、その銘柄が3期間移動平均線を上回って引けたら、大引けで手仕舞うことに

ローレンス・A・コナーズ他『高勝率システムの考え方と作り方と検証』(PanRolling、2014年)

ルールは基本的に上記の通りに作ります。しかし、1.については扱うデータが指数であるため、基本的に流動性はあるものだとして、無視します。

システムの構築

リファクタリングを行いましたので、今までと記法が若干変わります。幾分マシになったと思います。コードは下記のとおりです。

class Gap < Strategy

    attr_accessor :closes, :open

    def initialize
      @length = 4
    end

    def set_env
      @closes = Soks.parse(soks[0..-1], :close)
      @open = soks[-1].open
    end

    def decide(env)
      if position
        ave = closes[-3..-1].ave(3)[-1]
        if ave < closes[-1]
          return Action::Sell.new(code,date,closes[-1],1)
        end
      else
        gap_down = soks[-2].low > soks[-1].open
        rsi = closes[-3..-2].rsi(2)[-1]
        if rsi < 5 and gap_down
          return Action::Buy.new(code,date,open,1)
        end
      end
      return Action::None.new(code,open)
    end
  end

チャートを書いてみます。

profit_histgram

良さそうですね。ストップロスをおいてないので、下記のようなトレードもいくつかあります。

profit_histgram

検証

2007年から2017年の33業種別株価指数を用いて個別にバックテストを行います。結果は下記のとおりです。

Code Income Trades Win PF Average DD
I201 5.61 207 62.32 1.03 0.03 -20.69
I202 -63.44 232 55.6 0.8 -0.27 -38.21
I203 -33.49 222 58.56 0.86 -0.15 -17.84
I204 19.73 215 61.4 1.13 0.09 -26.23
I205 -51.1 216 57.87 0.77 -0.24 -24.43
I206 -71.82 196 58.16 0.72 -0.37 -20.02
I207 -18.97 232 60.78 0.91 -0.08 -23.05
I208 -19.21 213 56.81 0.89 -0.09 -22.66
I209 -91.36 210 59.05 0.69 -0.44 -34.54
I210 -80.11 229 53.28 0.74 -0.35 -34.69
I211 -55.63 234 58.55 0.81 -0.24 -39.97
I212 -168.23 225 51.11 0.58 -0.75 -21.94
I213 -76.3 237 54.01 0.76 -0.32 -37.16
I214 0.31 228 64.47 1.0 0.0 -23.05
I215 -72.11 243 57.61 0.77 -0.3 -29.59
I216 -22.5 251 62.15 0.91 -0.09 -35.14
I217 -131.29 242 57.02 0.6 -0.54 -50.09
I218 -39.33 228 64.91 0.83 -0.17 -31.54
I219 -57.36 235 58.3 0.78 -0.24 -35.18
I220 -56.78 197 58.38 0.76 -0.29 -57.3
I221 -11.47 202 59.41 0.93 -0.06 -17.52
I222 -220.58 226 49.12 0.52 -0.98 -46.51
I223 15.35 207 59.42 1.09 0.07 -23.22
I224 -38.71 233 58.37 0.85 -0.17 -24.71
I225 -24.13 199 55.78 0.86 -0.12 -13.91
I226 -124.51 231 56.71 0.61 -0.54 -40.16
I227 -41.08 212 56.13 0.79 -0.19 -15.82
I228 -120.33 225 52.89 0.66 -0.53 -30.22
I229 -211.01 238 46.64 0.53 -0.89 -71.6
I230 -86.99 219 55.25 0.72 -0.4 -38.89
I231 -145.66 228 54.39 0.64 -0.64 -34.43
I232 -87.75 232 55.17 0.75 -0.38 -48.73
I233 -0.48 224 62.95 1.0 -0.0 -25.24
平均 -66.1 223.0 57.3 0.8 -0.3 -31.9
偏差 59.47 13.71 4.0 0.15 0.26 12.56

勝率は57%と高めですが、とても使えるものではないですね。著書の結果では勝率は75%、平均損益も0.7%とかなり良いシステムなのですけども。個別銘柄を対象にした場合は結果が変わるのかもしれません。

養命酒2540を見てみます。2000年から2017年のデータを使っています。

======================================================
2540
net income:               170.8798905150817
profit | loss:            328.618207829292    | -157.73831731421015
average:                  0.5974821346681178
pf:                       2.1
max profit | max loss:    11.243243243243244     | -10.964083175803403
trades | wins | looses:   286     | 204     | 82
wins{%}                   71.3
max series of wins:       14
max series of looses:     5
average span{win}:        1
average span{loose}:      3
max drow down:            -13.085295297015524
bunkrupt:                 0.0
======================================================

かなりいい成績ですね。損益曲線を調べてみます。

profit_histgram

途中スランプはあったとしても、長期に渡って有効であるように感じます。

一方で、ソフトバンク9984を見てみますと、次のようになります。

======================================================
9984
net income:               -127.40634943983551
profit | loss:            726.6759200390887    | -854.0822694789244
average:                  -0.33006826279750134
pf:                       0.9
max profit | max loss:    17.22488038277512     | -29.369627507163326
trades | wins | looses:   386     | 232     | 154
wins{%}                   60.1
max series of wins:       13
max series of looses:     8
average span{win}:        1
average span{loose}:      4
max drow down:            -118.06053901093593
bunkrupt:                 0.0
======================================================

損益曲線を見てみます。

profit_histgram

なんだこれは。。。 序盤の暴落を抜けたあとは、比較的良いトレードを行っているようですが、序盤何に一体何があった?

チャートを見てみると、エグい暴落局面を拾っているようですね。

profit_histgram

profit_histgram

連日のストップ安なんかの局面はルールの1.を加えることで回避できた可能性もあります。

まとめ

ギャップを利用したシステムについて検証を行いました。33業種別株価指数ではあまり優位な結果を得ることができませんでしたが、個別に見ていくと良い成績が得られる可能性があることがわかりました。

やっぱシストレ本は読んでて本当に意味があるんかいなと懐疑的になってきますね。確かに評価方法を知れたのは収穫だったのですけども。

人が関わる以上過去のチャートの中に痕跡が残る、あるいはその痕跡をもとにトレードを行っているはずで、その中に優位な痕跡を見つけることができれば数打つことで優位を保証できるというのがシストレの大前提です。

問題なのは、そのパターンを移動平均やら、いくつかの指標を使って上手く抜けているかかどうか?ってところになると思います。

何とかしてパターンを特定しようとするわけですが、複数市場を対象にするだけでその特定が一気に困難になりました。

そこで一旦指標から離れて、もっと正確にパターンを抜くことを目標としていこうと思います。

パターン分類をしようとするとなると、クラスタ分析なんてのが良さげですが、今回はもっと単純に始めてみたいと思います。

テンプレートを作成し、それと規格化された株価との2乗距離を測定することでテンプレートに近いチャートの抜き出しを行いたいと思います。

では、さっそく参りましょう。

目次

実践

パターン抽出方法の説明

パターンの抽出は以下の方法で行います。

  1. テンプレートの作成
  2. 株価の規格化
  3. テンプレートと規格化された株価の二乗距離の測定
  4. 距離が規定値以下かどうかを判定

テンプレートの作成

テンプレートは0から1の間の50日分の点で作成します。例えば急落局面のテンプレートを作成しようとした場合は、次のようなグラフで書ける50個の点を用意することになります。

profit_histgram

株価の規格化

テンプレートは0〜1の値ですので、それに合わせて株価も0〜1の値を取るように弄くります。単純に50日間の株価の中で最小となる値を0、最大となる値を1として規格化を行います。式で書けば以下のようになります。

(株価t - 株価.MIN) / (株価.MAX - 株価.MIN)

テンプレートと規格化された株価の二乗距離の測定

あとはテンプレートと、株価との距離を測定します。各日において求めた二乗誤差の集計が二乗距離となります。つまり、

Σt50(テンプレートt - 規格化株価t)2

最後にこの距離が規定値以下の場合はテンプレートと同じ株価だと判定して終わりです。

コードにすると下記のようになります。

class Pattern
    attr_accessor :pattern, :thr

    def initialize(pattern)
      @thr = 1.5
      @pattern = Soks[*pattern]
    end

    def correspond?(target)
      size = @pattern.length
      min = target[-size..-1].min
      reg = target[-size..-1].max - min
      ts = target[-size..-1].map {|t| (t-min).to_f / reg}
      di = 0
      ts.zip(pattern).each do |t,p|
        di += (t - p) ** 2
      end
      di = Math.sqrt(di)
      @thr > di
    end
  end

実際にどういった株価が抽出されるのかを確認してみます。☓までがパターン一致部分でそれから20日ぶん表示してあります。

profit_histgram

N日検定

これで抜き出された株価は、指標を用いたシグナル判定に比べ、より似た値動きをしているはずです。

N日検定を用いて、その優位性を確認してみましょう。データは2007年から2017年の33業種別株価指数を用います。

ルールは次のようになります。

  • パターン判定されるかつ10日安値をつける。
  • 翌日の初値で売り。
  • N日経過で仕切り。

用いたパターンは上記のものです。コードにすれば下記のようになります。

      Pattern.new(40.times.map {|i| i.to_f/39} +
                  10.times.map {|i| 1.0 - i.to_f/9})
Code 5 10 15 20 30 50
I201 0.47 0.50 0.58 0.33 0.45 0.50
I202 0.58 0.45 0.45 0.36 0.18 0.36
I203 0.60 0.67 0.58 0.50 0.25 0.58
I204 0.33 0.44 0.33 0.33 0.29 0.33
I205 0.73 0.60 0.70 0.70 0.70 0.78
I206 0.43 0.44 0.53 0.47 0.35 0.43
I207 0.64 0.58 0.58 0.75 0.58 0.50
I208 0.57 0.67 0.50 0.58 0.50 0.50
I209 0.44 0.50 0.62 0.46 0.62 0.64
I210 0.38 0.33 0.43 0.43 0.43 0.50
I211 0.53 0.54 0.62 0.54 0.46 0.55
I212 0.72 0.64 0.69 0.62 0.54 0.58
I213 0.50 0.59 0.59 0.59 0.47 0.56
I214 0.50 0.50 0.54 0.54 0.54 0.77
I215 0.63 0.67 0.67 0.53 0.67 0.67
I216 0.54 0.80 0.70 0.50 0.60 0.67
I217 0.53 0.62 0.69 0.62 0.54 0.54
I218 0.38 0.43 0.38 0.46 0.42 0.50
I219 0.40 0.33 0.33 0.25 0.18 0.27
I220 0.73 0.43 0.36 0.43 0.29 0.55
I221 0.38 0.42 0.50 0.67 0.42 0.58
I222 0.56 0.50 0.50 0.50 0.43 0.55
I223 0.50 0.50 0.58 0.42 0.36 0.78
I224 0.46 0.58 0.42 0.42 0.50 0.70
I225 0.64 0.60 0.60 0.40 0.40 0.56
I226 0.39 0.63 0.56 0.56 0.44 0.54
I227 0.63 0.67 0.67 0.64 0.57 0.62
I228 0.43 0.60 0.50 0.50 0.50 0.60
I229 0.73 0.55 0.64 0.55 0.45 0.60
I230 0.61 0.57 0.43 0.50 0.57 0.54
I231 0.90 0.75 0.63 0.75 0.50 0.75
I232 0.58 0.36 0.45 0.64 0.64 0.36
I233 0.43 0.33 0.33 0.25 0.36 0.36
平均 0.53 0.53 0.53 0.50 0.45 0.54

N日検定はN日によらず勝率55%を超えることで、その仕掛けの優位を確認する検定です。この結果はそれに到底及びませんが、私が行ってきた今までの結果からすればましな結果になっています。

少しは期待できるかもしれません。

検証

仕切りを10日安値をつけたら買い戻しとして、バックテストを行ってみます。データは同じものを使います。

Code Income Trades Win PF Average DD
I201 10.13 12 50.0 1.51 0.84 -10.63
I202 5.17 11 27.27 1.14 0.47 -23.81
I203 1.58 12 41.67 1.09 0.13 -5.87
I204 -15.23 17 29.41 0.53 -0.9 -11.25
I205 14.61 10 60.0 2.54 1.46 -8.33
I206 -12.98 17 35.29 0.73 -0.76 -32.12
I207 24.36 12 50.0 2.63 2.03 -12.35
I208 -0.73 12 41.67 0.96 -0.06 -12.62
I209 -4.36 13 38.46 0.89 -0.34 -16.95
I210 -45.29 15 13.33 0.26 -3.02 -28.76
I211 -9.7 13 38.46 0.69 -0.75 -13.08
I212 51.82 13 61.54 3.18 3.99 -9.09
I213 -4.72 17 52.94 0.89 -0.28 -12.28
I214 6.66 14 50.0 1.27 0.48 -9.3
I215 19.62 16 43.75 1.76 1.23 -14.1
I216 30.7 10 60.0 4.22 3.07 -7.03
I217 7.52 13 46.15 1.37 0.58 -15.51
I218 -5.7 13 23.08 0.78 -0.44 -14.66
I219 -14.37 12 25.0 0.61 -1.2 -19.33
I220 -19.41 14 42.86 0.41 -1.39 -20.21
I221 -5.18 12 33.33 0.72 -0.43 -15.04
I222 -1.14 14 28.57 0.97 -0.08 -35.81
I223 -13.51 12 33.33 0.44 -1.13 -19.11
I224 -11.08 12 25.0 0.61 -0.92 -12.59
I225 4.46 10 60.0 1.41 0.45 -4.56
I226 23.56 16 50.0 1.73 1.47 -18.2
I227 20.65 15 53.33 2.24 1.38 -4.71
I228 27.83 10 40.0 2.09 2.78 -10.95
I229 34.16 11 63.64 2.38 3.11 -9.03
I230 1.31 14 50.0 1.05 0.09 -9.38
I231 24.53 8 75.0 4.97 3.07 -4.31
I232 -7.56 11 45.45 0.78 -0.69 -20.24
I233 -6.93 12 33.33 0.61 -0.58 -6.78
平均 4.0 12.0 43.1 1.4 0.4 -14.2
分散 18.85 2.24 13.58 1.08 1.54 7.55

トレード数が少ないのでなんとも言い難いですが、期待していたほどではありませんね。

まとめ

二乗距離を用いて、テンプレートに一致するかの判定を行い、仕掛けのルールに組み込んでみました。ものは試しに程度のことしか行っていませんが、いじり方によっては期待ができそうな気はします。

みなさんはふるさと納税してますか?私は去年か一昨年だかに初めてやってみまして、山形県寒河江市の米、はえぬきですかね、を返礼品として頂きました。一人暮らしの我が家にドカドカと米が届きまして、当面米に困ることはありませんでした。お米は美味しいのでおすすめです。まだやったことのない方は調べてみてはいかがでしょうか?

さて、このサイトはRubyでバックテストツールを作成し様々なストラテジーを検証することを目的としています。前回はKAMAを用いたシステムを著書とは別の方法で作成し検証を行いました。検証したシステムはまだまだ改善の余地がありましたが、その方向性は悪くなかったと思います。

KAMAは指数平滑移動平均の平滑化定数をボラティリティによって指定の範囲で増減させる指標でした。今回はVIDYAという似たような別の指標を使ってシステムを構築し検証していきたいと思います。

では参りましょう。

目次

実践

VIDYAとは

ぱっとVIDYAを検索かけてみると、なかなか情報が錯綜しているように見えますね。この辺はあまり馴染みがなさそうに見受けられます。VIDYA(Variable Index Dinamic Average)は1992年にシャンデ氏が発表した指標とされています。株価のボラティリティによって平滑化定数が変動する指数平滑化移動平均の一つです。ボラティリティをVI、平滑化定数をαとして、次のようにかけます。

VIDYA = 前日VYDIA + α VI (終値 - 前日VIDYA)

このVIには色々な指標を用いることが出来るのですが、ここに標準偏差の比率を選択すると一般的にVIDYAと呼ばれるようです。すなわち

VI = STDEV(終値,短期期間) / STDEV(終値,長期期間)

となります。またαは平滑化定数ですので、平滑化の期間をNとして下記のようにかけます。

α = 2 / ( 1 + N)

後になってシャンデ氏がVIにCMO(Chande Momentum Ocillator)を用いるようになります。この場合はVMA(Variable Moving Average)などと呼ぶようです。今回はVIDYAを利用するのでCMOについては説明しませんが(知ってもいませんが)、VIは0〜1の値である必要があるため、CMOを利用する場合は絶対を取って100でわる必要があります。あるいは標準偏差の比率を用いた場合は1を超える場合があるので、1にクリップする必要があります。またVIに前回のKAMAで利用したER(Effeciency Racio)を用いることなどもできます。

式を眺めますと、VIが1に近づいた場合はN日の指数平滑移動平均に近づき、VIが0に近づいた場合は∞日の指数平滑化移動平均に近づくことがわかります。つまり、前日VIDYAと一致します。

KAMAには平滑化の期間に上限、下限があったのに対して、VIDYAには下限のみが存在することになります。

名前なんかどうでもいいんだよ計算できりゃー。てなわけで次に進みましょう。

売買ルール

著書には明確にルールが説明されていませんが、チャートを見ていると終値とVIDYAのクロスで売買しているようです。著書に従ってストラテジーを構築します。と言いたいところですが、パラメータが明示されてないですね。。。Nには39日を設定したとありますので、それを利用しますが、標準偏差の期間については明示されていません。適当に7と39くらいにしときますか。 一応ルールを書けば下記のようになります。

  • 終値 > VIDYA ならば どてん買い
  • 終値 < VIDYA ならば どてん売り
  • 翌日初値で注文
  • ロスカットなし

ちなみにこの著者はNを39にした理由を条件を一致させるためとしていますが、KAMAの場合は上限を36日(≒39)に設定しVIDYAの場合は下限を39日に設定していることになるため、条件は一致していません。ですが著書にはこれで良い結果が出たと書いてあるので同じように39日を使います。

ストラテジーの構築

コードはこのようになります。

class Vidya

    attr_accessor :length, :l_len, :s_len

    def initialize
      @length = 40
      @l_len = 39
      @s_len = 7
      @alpha = 2.0 / (1 + 39)
      @vidya = nil
    end

    def set_env(soks, env)
      env[:closes] = Soks.parse(soks[0..-2],:close)
      env[:open] = soks[-1].open
    end

    def setup
      @vidya = nil
    end

    def decide(env)
      code = env[:code]
      open = env[:open]
      date = env[:date]
      position = env[:position]
      closes = env[:closes]

      @vidya = calc_ave(closes)
      is_buy = closes[-1] > @vidya
      is_sell = closes[-1] < @vidya

      if position
        if is_buy and position.sell?
          return Action::Buy.new(code, date, open, 2)
        elsif is_sell and position.buy?
          return Action::Sell.new(code, date, open, 2)
        else
          return Action::None.new(code,open)
        end
      end

      if is_buy
        return Action::Buy.new(code, date, open, 1)
      elsif is_sell
        return Action::Sell.new(code, date, open, 1)
      else
        return Action::None.new(code,open)
      end
    end

    def calc_ave(closes)
      if @vidya.nil?
        @vidya = closes[-1]
      else
        sdev = closes[-@s_len..-1].dev(@s_len)
        ldev = closes[-@l_len..-1].dev(@l_len)
        vi = sdev / ldev
        vi = 1 if vi > 1
        @vidya = @vidya + @alpha * vi * (closes[-1] - @vidya)
      end
      @vidya
    end
  end

チャートを書いていきます。終値とのクロスですので非常に騙しが多いですが、豪快に取れるときは素晴らしいですね。

profit_histgram

profit_histgram

あとは、期待するわけでもなく同じ手順を繰り返していきます。

N日検定

N日検定を行った結果は下記です。2007年から2017年の期間で33業種別株価指数を用いて検定を行っています。Nは5,10,15,20,30,50です。

Code 5 10 15 20 30 50
I201 0.52 0.44 0.53 0.50 0.53 0.46
I202 0.53 0.52 0.49 0.44 0.47 0.47
I203 0.47 0.42 0.38 0.47 0.45 0.39
I204 0.44 0.55 0.50 0.47 0.33 0.43
I205 0.49 0.41 0.44 0.53 0.31 0.59
I206 0.45 0.52 0.45 0.52 0.51 0.52
I207 0.45 0.46 0.50 0.47 0.46 0.46
I208 0.56 0.51 0.46 0.46 0.48 0.52
I209 0.43 0.48 0.64 0.53 0.56 0.46
I210 0.47 0.49 0.52 0.53 0.51 0.43
I211 0.42 0.51 0.42 0.52 0.49 0.52
I212 0.56 0.52 0.60 0.59 0.48 0.44
I213 0.49 0.52 0.62 0.47 0.50 0.50
I214 0.55 0.47 0.51 0.51 0.46 0.42
I215 0.42 0.54 0.49 0.47 0.50 0.46
I216 0.46 0.51 0.46 0.43 0.45 0.42
I217 0.47 0.52 0.52 0.52 0.63 0.48
I218 0.46 0.33 0.34 0.48 0.41 0.50
I219 0.54 0.49 0.43 0.46 0.55 0.60
I220 0.49 0.57 0.54 0.48 0.36 0.48
I221 0.52 0.36 0.32 0.35 0.40 0.52
I222 0.51 0.46 0.44 0.54 0.47 0.58
I223 0.49 0.50 0.49 0.51 0.43 0.40
I224 0.52 0.51 0.53 0.42 0.38 0.59
I225 0.47 0.47 0.58 0.44 0.31 0.53
I226 0.56 0.52 0.51 0.47 0.49 0.47
I227 0.47 0.45 0.41 0.41 0.46 0.55
I228 0.55 0.59 0.51 0.51 0.49 0.57
I229 0.60 0.63 0.58 0.71 0.65 0.48
I230 0.51 0.48 0.46 0.51 0.53 0.55
I231 0.59 0.61 0.71 0.70 0.50 0.54
I232 0.45 0.61 0.58 0.60 0.53 0.48
I233 0.43 0.42 0.41 0.60 0.58 0.54
平均 0.49 0.50 0.50 0.50 0.47 0.50

ですよね。

銘柄間の分散測定

バックテストをN日検定と同一の条件で行って、銘柄間の分散を調べていきます。SMA1×39のバックテストの結果と比較してみます。

  • VIDYA
Code Income Trades Win PF Average DD
I201 52.29 155 27.1 1.33 0.34 -17.86
I202 -116.35 179 22.91 0.68 -0.65 -33.06
I203 -92.67 158 24.05 0.64 -0.59 -36.0
I204 -81.32 197 20.3 0.63 -0.41 -41.67
I205 -23.63 170 27.65 0.89 -0.14 -54.34
I206 -39.2 163 26.38 0.84 -0.24 -38.4
I207 36.47 169 29.59 1.2 0.22 -13.93
I208 -47.31 189 22.75 0.76 -0.25 -49.54
I209 -74.49 199 21.11 0.75 -0.37 -32.5
I210 -178.81 243 23.46 0.55 -0.74 -48.12
I211 48.26 152 26.32 1.22 0.32 -26.38
I212 128.24 111 33.33 1.71 1.16 -28.52
I213 -7.4 145 23.45 0.97 -0.05 -26.72
I214 23.18 153 25.49 1.12 0.15 -27.21
I215 80.27 138 29.71 1.43 0.58 -16.64
I216 140.68 121 35.54 1.99 1.16 -18.9
I217 100.23 132 29.55 1.56 0.76 -22.7
I218 -40.13 165 23.64 0.83 -0.24 -26.78
I219 26.6 133 24.06 1.12 0.2 -29.71
I220 70.43 143 29.37 1.43 0.49 -29.17
I221 -5.34 183 28.96 0.97 -0.03 -19.92
I222 72.5 132 28.03 1.25 0.55 -36.31
I223 41.22 149 30.87 1.22 0.28 -43.22
I224 -62.69 177 22.6 0.73 -0.35 -25.31
I225 -74.42 213 22.54 0.69 -0.35 -27.22
I226 -16.07 144 28.47 0.93 -0.11 -28.71
I227 -7.53 164 26.83 0.96 -0.05 -23.91
I228 91.61 134 26.87 1.49 0.68 -33.52
I229 248.12 108 30.56 2.28 2.3 -21.16
I230 14.84 154 26.62 1.06 0.1 -40.86
I231 0.85 180 25.56 1.0 0.0 -46.85
I232 20.19 126 27.78 1.08 0.16 -53.59
I233 36.14 143 21.68 1.25 0.25 -19.1
平均 11.1 158.0 26.5 1.1 0.2 -31.4
偏差 82.06 28.98 3.51 0.39 0.59 10.8
  • SMA1×65
Code Income Trades Win PF Average DD
平均 2.6 165.0 28.5 1.0 0.1 -33.7
偏差 74.03 17.35 4.25 0.26 0.46 10.71

以外に悪くないですね。取引コストを勘定していないので、それを入れるととんとんと言ったところでしょうか。騙しのフィルターを加えると大分成績が上がるような気がします。

損益分析

収益の良いI229の損益分析を行ってみましょう。

======================================================
net income:               248.12273587116596
profit | loss:            442.4213703271667    | -194.29863445600074
average:                  2.297432739547833
pf:                       2.3
max profit | max loss:    145.5657136202178     | -10.358867244850071
trades | wins | looses:   108     | 33     | 75
wins{%}                   30.6
max series of wins:       2
max series of looses:     10
average span{win}:        61
average span{loose}:      6
max drow down:            -21.155972535376836
bunkrupt:                 0.0
======================================================
  • 損益曲線

profit_histgram

  • 損益ヒストグラム

profit_histgram

  • 月次損益

profit_histgram

おや?これはなかなかいい感じじゃないでしょうか?クロスで仕掛けるシステムとして結構理想的な収益曲線を描けているように感じます。いじっくっていくと期待できるのではないでしょうか?

まとめ

KAMAに続き、VIDYAを使ってシステムを作成し検証を行いました。VIDYAとKAMAで条件は異なるため、比較は行なえませんがVIDYAは簡単なシステムながらポテンシャルを秘めていることがわかりました。

前回は「トレードシステムはどう作ればよいか①」よりKAMAとLAMAを用いて、そのクロスで売買を行うシステムを検証しました。KAMAはペリーカウフマンによって考案された、ボラティリティによって時間軸が変動する適応型の指数平滑移動平均です。LAMAはそれに遅延して追随する指標でした。

用いるパラメータは著書のとおりに設定し、2007年から2017年の33業種別株価指数に対してバックテストを行いました。しかし、たいして優位な結果を得ることができませんでした。

KAMAは広いレンジでダイナミックに時間軸が変動することに意味があると私は考えています。したがって、9日〜36日と比較的短いレンジではKAMAを使う意味がないのではないかと。

そこで、今回はまずレンジを16日〜900日に設定してLAMAとのクロスにより売買を行った場合、どのような結果になるのかを検証してみたいと思います。

その後、このKAMAを用いて別のシステムを作ってみたので、それを検証して行きたいと思います。

では、見ていきましょう。

目次

実践

KAMAのパラメータ変更による効果

KAMA、LAMAのパラメータを変更して検証を行います。その他の売買ルールは前回と変わりません。パラメータは共に(10,4,30)を用います。10は時間軸を変動させるためのボラティリティを求めるための日数で、4,30はそれぞれ時間軸の下限と上限の平方根です。したがってこのパラメータのKAMAは16日〜900日の間で変動する平滑化定数を用いた指数平滑移動平均となります。

バックテストを行って銘柄間の分散を調べます。

  • (10,4,30)
Code Income Trades Win PF Average DD
I201 9.24 19 31.58 1.1 0.49 -46.4
I202 -80.04 20 25.0 0.47 -4.0 -56.89
I203 12.95 19 10.53 1.1 0.68 -76.2
I204 25.44 16 18.75 1.29 1.59 -35.05
I205 23.73 18 27.78 1.29 1.32 -63.7
I206 -82.96 28 25.0 0.57 -2.96 -83.48
I207 31.19 20 20.0 1.28 1.56 -44.59
I208 -25.28 26 19.23 0.79 -0.97 -43.42
I209 -42.24 20 25.0 0.64 -2.11 -43.58
I210 -122.29 38 13.16 0.51 -3.22 -159.23
I211 58.18 16 31.25 1.72 3.64 -43.65
I212 3.43 22 31.82 1.02 0.16 -95.1
I213 -62.48 20 15.0 0.6 -3.12 -82.43
I214 -40.5 22 18.18 0.69 -1.84 -46.61
I215 42.93 16 31.25 1.5 2.68 -54.31
I216 90.9 16 37.5 2.17 5.68 -31.87
I217 20.83 17 29.41 1.21 1.23 -58.53
I218 -12.87 17 11.76 0.9 -0.76 -86.97
I219 100.19 16 37.5 2.6 6.26 -24.07
I220 41.73 24 41.67 1.47 1.74 -22.48
I221 32.89 16 37.5 1.46 2.06 -27.31
I222 79.0 21 38.1 1.72 3.76 -39.74
I223 87.17 16 43.75 2.55 5.45 -23.13
I224 1.66 20 20.0 1.02 0.08 -69.77
I225 0.72 20 15.0 1.01 0.04 -62.68
I226 -48.96 22 22.73 0.59 -2.23 -52.52
I227 3.57 20 20.0 1.03 0.18 -68.68
I228 59.18 18 33.33 1.63 3.29 -45.5
I229 97.72 18 33.33 1.61 5.43 -86.0
I230 -13.13 24 29.17 0.92 -0.55 -54.27
I231 -45.27 24 16.67 0.78 -1.89 -125.36
I232 34.7 20 15.0 1.25 1.73 -96.88
I233 35.73 18 16.67 1.5 1.98 -45.95
平均 9.6 20.0 25.5 1.2 0.8 -60.5
偏差 54.1 4.36 9.17 0.53 2.69 29.4
  • (10,3,9)
平均 -6.6 73.0 29.7 1.0 0.0 -49.9
偏差 75.22 9.0 5.14 0.29 1.02 20.83

トレード回数が激減しましたね。。。収益は改善しましたが、DDが微妙です。うーん、そもそも使えませんし、どっともどっちと言ったところでしょうか?

KAMA-STCを使ったCB-PBのルール

クロスをトリガーとするシステムには向かないのでは?ということで、別のアプローチでシステムを作っていきます。KAMAはN日前と当日の終値の差が少なくなると、一気に変動が少なくなる指標です。したがって、押し目を作りながら上昇していくようなチャートに対して、KAMAは階段状のチャートを形成していきます。

そこでKAMAに対してストキャスティックを適用し、100と0をそれぞれ上昇局面と下降局面であると定義します。そして、それぞれの押し目で仕掛けていきます。

  • 仕掛け
    • KAMA-STC = 100
      • 終値 < KAMA + DEV * 0.3
    • KAMA-STC = 0
      • 終値 > KAMA - DEV * 0.3
    • KAMA-STC ≡ (KAMA-KAMA.MIN) / (KAMA.MAX-KAMA.MIN)
    • DEV ≡ √(Σ(終値-KAMA)**2/N)
    • 翌日初値
  • 仕切り
    • 利益 > 0
      • トレイリングストップ 5日で利確
    • それ以外
      • 仕掛けの条件でドテン
    • トレインリングストップ ≡ 過去N日間の安値 = 今日の安値の場合売り (またはその逆)
    • 翌日初値
  • ロスカットなし

KAMA-STCを計算するための期間は10日とします。

バックテストは2007年から2017年の33業種別株価指数を用いて、単利で行います。

ストラテジーの構築

コードはこんな感じです。KAMAの計算については前回の記事を参照願います。

class KamaEmb < KamaLama

    attr_accessor :kmasa_l, :t_stop_l, :length

    def initialize
      @kamas = Soks.new
      @t_stop_l = 5
      @m_stop = 0
      @kamas_l = 10
      @dev_r = 0.3
      @length = [@kamas_l,@t_stop_l].max + 2
    end

    def m=(m)
      @m = m
      @length = [@m,@length].max
    end

    def set_env(soks, env)
      super
      env[:soks] = soks[0..-2]
    end

    def decide(env)
      code = env[:code]
      open = env[:open]
      date = env[:date]
      position = env[:position]
      closes = env[:closes]
      soks = env[:soks]

      @kama, @lama = calc_ave(closes)
      @kamas << @kama
      return Action::None.new(code,open) if @kamas.length < @kamas_l
      dev = closes[-@kamas_l..-1].vol(@kamas_l,@kamas)[-1]
      stc = (@kamas.last - @kamas.min ) / (@kamas.max - @kamas.min)  * 100
      is_buy_p = @is_buy
      is_sell_p = @is_sell
      @is_buy = (stc == 100 and closes[-1] < @kama+dev*@dev_r)
      @is_sell = (stc == 0 and closes[-1] > @kama-dev*@dev_r)

      @kamas.shift

      if position
        gain = position.gain(closes[-1], position.volume)

        if gain > @m_stop
          high = soks[-@t_stop_l..-1].high(@t_stop_l)[-1]
          low = soks[-@t_stop_l..-1].low(@t_stop_l)[-1]
          if position.sell? and high == soks[-1].high
            return Action::Buy.new(code, date, open, 1)
          elsif  position.buy? and low == soks[-1].low
            return Action::Sell.new(code, date, open, 1)
          else
            return Action::None.new(code,open)
          end
        else
          if @is_buy and not is_buy_p and position.sell?
            return Action::Buy.new(code, date, open, 2)
          elsif @is_sell and not is_sell_p and position.buy?
            return Action::Sell.new(code, date, open, 2)
          else
            return Action::None.new(code,open)
          end
        end
      end

      if @is_buy and not is_buy_p
        return Action::Buy.new(code, date, open, 1)
      elsif @is_sell and not is_sell_p
        return Action::Sell.new(code, date, open, 1)
      if @is_buy and not is_buy_p
        return Action::Buy.new(code, date, open, 1)
      elsif @is_sell and not is_sell_p
        return Action::Sell.new(code, date, open, 1)
      else
        return Action::None.new(code,open)
      end
    end
  end

大分救いようがなくなってきました。チャートを書いてみます。

profit_histgram

profit_histgram

比較的短い周期で勝ちを重ねていきますが、負けるときは盛大に負けています。

検証

順々に見ていきます。N日検定を行います。N には5,10,15,20,30,50を使います。

Code 5 10 15 20 30 50
I201 0.44 0.51 0.51 0.53 0.45 0.47
I202 0.46 0.43 0.39 0.46 0.47 0.38
I203 0.42 0.45 0.46 0.53 0.53 0.53
I204 0.56 0.45 0.41 0.41 0.44 0.42
I205 0.58 0.55 0.65 0.53 0.48 0.53
I206 0.52 0.45 0.52 0.52 0.45 0.53
I207 0.58 0.49 0.55 0.57 0.58 0.62
I208 0.48 0.52 0.47 0.62 0.44 0.50
I209 0.51 0.53 0.52 0.52 0.42 0.36
I210 0.47 0.46 0.44 0.55 0.45 0.43
I211 0.53 0.56 0.58 0.51 0.54 0.58
I212 0.51 0.47 0.56 0.53 0.62 0.55
I213 0.49 0.60 0.61 0.68 0.62 0.72
I214 0.48 0.46 0.43 0.53 0.52 0.53
I215 0.55 0.49 0.45 0.59 0.52 0.48
I216 0.44 0.42 0.52 0.50 0.63 0.53
I217 0.51 0.58 0.49 0.48 0.48 0.37
I218 0.48 0.48 0.42 0.55 0.47 0.48
I219 0.57 0.50 0.45 0.53 0.65 0.53
I220 0.55 0.41 0.44 0.37 0.44 0.50
I221 0.53 0.58 0.60 0.61 0.54 0.47
I222 0.59 0.59 0.59 0.53 0.62 0.58
I223 0.49 0.56 0.61 0.56 0.58 0.42
I224 0.46 0.40 0.43 0.46 0.44 0.41
I225 0.51 0.52 0.53 0.44 0.53 0.47
I226 0.50 0.46 0.54 0.56 0.61 0.47
I227 0.55 0.51 0.52 0.59 0.60 0.49
I228 0.56 0.53 0.59 0.50 0.54 0.56
I229 0.52 0.45 0.54 0.48 0.44 0.53
I230 0.57 0.54 0.65 0.62 0.50 0.61
I231 0.51 0.57 0.55 0.45 0.50 0.58
I232 0.64 0.72 0.54 0.59 0.56 0.63
I233 0.51 0.61 0.60 0.53 0.53 0.55
平均 0.52 0.51 0.52 0.53 0.52 0.51

この検定は仕掛けに対しN日後で仕切った場合、N日によらず55%を超えることで、仕掛けの優位を確認するものです。しかし今のところ55%なんて数字は出た試しがありません。この数字は今までで一番良いのじゃないでしょうか。

続いて銘柄ごとにバックテストを行い結果の偏差を見ていきます。

Code Income Trades Win PF Average DD
I201 -2.9 66 53.03 0.98 -0.04 -32.97
I202 49.36 84 65.48 1.32 0.59 -40.87
I203 -15.01 84 55.95 0.87 -0.18 -44.73
I204 -51.03 81 66.67 0.67 -0.63 -55.29
I205 25.53 93 62.37 1.21 0.27 -21.13
I206 13.6 98 55.1 1.09 0.14 -28.28
I207 103.62 80 62.5 2.19 1.3 -13.83
I208 43.7 81 62.96 1.58 0.54 -10.39
I209 76.65 78 66.67 1.6 0.98 -19.45
I210 91.77 82 59.76 1.8 1.12 -15.37
I211 113.52 70 67.14 2.24 1.62 -18.74
I212 135.82 83 66.27 2.03 1.64 -22.87
I213 64.33 68 67.65 1.51 0.95 -27.24
I214 -25.59 76 52.63 0.82 -0.34 -21.63
I215 -7.53 83 54.22 0.96 -0.09 -23.17
I216 65.92 75 69.33 1.69 0.88 -25.25
I217 64.74 80 56.25 1.46 0.81 -28.74
I218 -5.67 80 57.5 0.97 -0.07 -35.37
I219 73.05 74 68.92 1.6 0.99 -33.17
I220 -3.79 72 58.33 0.96 -0.05 -23.8
I221 17.36 82 65.85 1.18 0.21 -25.02
I222 88.65 71 70.42 1.62 1.25 -31.46
I223 58.25 84 61.9 1.45 0.69 -26.68
I224 39.81 83 56.63 1.32 0.48 -21.73
I225 14.85 91 54.95 1.15 0.16 -27.03
I226 -24.02 75 53.33 0.85 -0.32 -29.97
I227 50.22 82 62.2 1.48 0.61 -16.7
I228 101.16 88 67.05 1.81 1.15 -19.3
I229 139.36 74 68.92 2.25 1.88 -20.08
I230 148.42 80 65.0 2.21 1.86 -29.8
I231 118.27 80 61.25 1.81 1.48 -22.23
I232 119.99 73 69.86 2.05 1.64 -24.13
I233 4.49 76 60.53 1.06 0.06 -22.47
平均 51.1 79.0 62.0 1.4 0.7 -26.0
偏差 53.22 6.86 5.52 0.45 0.69 8.83

パラメータは調整しましたが、まずまずの結果じゃないでしょうか?取引コストを考慮してませんが、平均収益が0.7%あるので十分プラスになると思われます。ただ、偏差が大きいので銘柄を絞りこめる必要がありますね。勝率は多くの銘柄で60%を超えてるので、チャートにあった大負けが発生してもなんとかなるのでしょう。

パラメータを弄っても、大負け大勝ちする銘柄は決まっています。何が影響しているのかを調べる必要があります。

I230の損益分析を行います。

======================================================
net income:               149.94356260678595
profit | loss:            270.73463561464536    | -120.79107300785935
average:                  1.8980197798327334
pf:                       2.2
max profit | max loss:    26.391543119229144     | -29.795831211708073
trades | wins | looses:   79     | 52     | 27
wins{%}                   65.8
max series of wins:       6
max series of looses:     4
average span{win}:        13
average span{loose}:      19
max drow down:            -29.795831211708073
bunkrupt:                 0.0
======================================================
  • 損益曲線

profit_histgram

  • 損益ヒストグラム

profit_histgram

  • 月次損益

profit_histgram

細かい勝ちを積み重ねるシステムの割には大勝ちに依存していますね。うーん。成績は良いですが、ちょっと期待していた損益曲線にはならなかったようです。

まとめ

まずKAMAとLAMAを使ったクロスによるシステムを検証しました。劇的な変化はありません。続いてKAMA-STCを使ってCB-PBシステムを検証しました。今までの中では一番まともなシステムだと思います。システムとしては課題が残っていますが、弄っていく価値はあるかもしれません。

このサイトはRubyでバックテストツールを作成し様々なストラテジーを検証することを目的としています。前回から「トレードシステムはどう作ればよいのか①」ジョージ・プルートの検証を開始しています。DBSを適用して移動平均線の長さをボラに応じて変化させるシステムについて検証を行いました。

この著書には他にいくつかの移動平均線の長さを動的に変化させるシステムについて触れられていますので、同じように検証を行っていきたいと思います。

今回紹介するのはペリーカウフマンが1995年に「Smarter Trading」にて紹介したとされるKAMA(カウフマン・アダプティブ・ムービング・アベレージ)を用いたシステムです。

では見ていきましょう。

目次

実践

KAMAとは

KAMAにある背景はこのように説明されています。

KAMAは、ノイズの大きな市場はノイズの少ない市場よりもトレンドがゆっくりと形成されなければならないことをベースとするものである。つまり、ノイズの大きな(ボラティリティの高い)市場では遅延の大きな移動平均を使い、トレンド市場では遅延の小さな移動平均を使用すべきということである。

ジョージ・プルート『トレードシステムはどう作ればよいのか①』(PanRolling、2013年)

基本的にはボラが増えてるときは移動平均の長さを長くし、減ってるときは短くする。というルールですので思想は前回と変わっていませんね。

KAMAは私に馴染みのないインジケータなので、まずはそちらを説明します。 KAMAを計算するには3つの定数を用います。

  • ERを計算するための期間
  • FastEMA〃の平方根
  • SlowEMA〃の平方根

ここでは上記の定数を上から(10,2,30)として説明します。ERの計算はこのように行います。

Change = (終値 - 10日前終値).Abs
Vol = Sum((終値 - 前日終値).Abs,10日)
ER = Change / Vol

したがって、ERは0〜1の間の数値であり、10日間の間終値が上昇し続けた場合ERは1となり、10日前と今日の終値が一致する場合は0となります。

KAMAは指数移動平均の平滑化定数をこのERによって変化させるものです。したがって平滑化定数をαとするとKAMAは次のようにかけます。

KAMA = 前日KAMA + α (終値 - 前日KAMA)

そしてαは次のように計算します。

F = 2 / (FastEMA〃の平方根 + 1)
S = 2 / (SlowEMA〃の平方根 + 1)
α = (ER (F - S) + S) ** 2

式を眺めると、ERが0のときは遅行指数移動平均の平滑化定数の2乗になり、ERが1のときは先行移動平均の平滑化定数の2乗になります。ですからαはERの値によって、遅行指数移動平均の平滑化定数と先行指数移動平均の定数を変動する値となることがわかります。

となると、ボラの大きい場合はSlow、小さい場合はFastの指数移動平均を使っていく指標だということがわかりますね。(10,2,30)のKAMAの場合は4日から900日の指数移動平均の値を変動する指数となります。

売買ルールの説明

このKAMAを用いて移動平均のクロスによって売買をするシステムが紹介されているのですが、著書によると、先行移動平均としてKAMA(10,3,6)を遅行移動平均としてLAMA(10,3,6)を用いたとあります。このLAMAはKAMAと同じようにαを求め更に0.5をそれに乗じます。つまり

LAMA = 前日LAMA + 0.5 α (KAMA - 前日LAMA)

となります。KAMAの2倍の長さの遅行指数移動平均みたいなものですかね。あとは普段通りのルールです。

ストラテジーの構築

コードはこのようになります。

class KamaLama

    attr_accessor :length, :s_len, :l_len, :n

    def initialize
      @length = 37
      @l_len = 6
      @s_len = 3
      @kama = nil
      @lama = nil
      @m = 10
    end

    def set_env(soks, env)
      env[:closes] = Soks.parse(soks[0..-2],:close)
      env[:open] = soks[-1].open
    end

    def setup
      @kama = nil
      @lama = nil
      @pkama = nil
      @plama = nil
    end

    def decide(env)
      code = env[:code]
      open = env[:open]
      date = env[:date]
      position = env[:position]
      closes = env[:closes]

      @kama, @lama = calc_ave(closes)

      if position
        if @kama > @lama and position.sell?
          return Action::Buy.new(code, date, open, 2)
        elsif @kama < @lama and position.buy?
          return Action::Sell.new(code, date, open, 2)
        else
          return Action::None.new(code,open)
        end
      end

      if @kama > @lama
        return Action::Buy.new(code, date, open, 1)
      elsif @kama < @lama
        return Action::Sell.new(code, date, open, 1)
      else
        return Action::None.new(code,open)
      end
    end

    def calc_ave(closes)
      @pkama, @plama = @kama, @lama
      er = (closes[-1] - closes[-@m]).abs / closes[-@m-1..-1].diff.abs.sum
      alpha = (er*(2.0/(@s_len+1) - 2.0/(@l_len+1)) + 2.0/(@l_len+1)) ** 2
      if not @kama or not @lama
        @kama = closes[-@l_len**2..-1].ave(@l_len**2)[-1]
        @lama = @kama
      else
        @kama = @kama + alpha * (closes[-1] - @kama)
        @lama = @lama + 0.5 * alpha * (@kama - @lama)
      end
      [@kama, @lama]
    end
  end

チャートは6日と36日の移動平均を使っています。次のように騙しを消せてる局面もありましたが、大方、SMAと同じように騙しで損してるよに見えます。KAMAは2乗することで、移動平均の長さをダイナミックに変化させることに意味があって、36日ってのは短いのかもしれません。

profit_histgram

profit_histgram

N日検定

N日検定をかけます。

ここでお詫びです。クロスでの仕掛けを利用したシステムのN日検定のコードに不備がありました。検定以外の場合は今日だけを見て先行線が遅行線の上にあるか下にあるかを判定すれば十分ですが、N日で仕切った場合、再エントリーは前日と今日の指標を使ってクロスの判定を行う必要がありました。追って過去記事にも修正を加えたいと思います。

Code 5 10 15 20 30 50
I201 0.57 0.42 0.46 0.42 0.59 0.56
I202 0.46 0.49 0.40 0.36 0.43 0.47
I203 0.56 0.52 0.45 0.53 0.55 0.55
I204 0.39 0.47 0.50 0.37 0.40 0.41
I205 0.45 0.43 0.48 0.50 0.50 0.46
I206 0.54 0.55 0.52 0.48 0.51 0.53
I207 0.58 0.49 0.52 0.53 0.53 0.40
I208 0.56 0.54 0.46 0.48 0.50 0.34
I209 0.45 0.46 0.43 0.49 0.61 0.52
I210 0.42 0.45 0.47 0.44 0.50 0.52
I211 0.55 0.50 0.56 0.55 0.44 0.54
I212 0.40 0.46 0.48 0.45 0.44 0.52
I213 0.49 0.47 0.66 0.58 0.46 0.57
I214 0.54 0.39 0.46 0.51 0.50 0.50
I215 0.46 0.48 0.47 0.47 0.47 0.55
I216 0.50 0.45 0.46 0.56 0.46 0.44
I217 0.52 0.56 0.51 0.43 0.54 0.48
I218 0.55 0.45 0.45 0.48 0.55 0.63
I219 0.52 0.50 0.49 0.46 0.45 0.54
I220 0.49 0.48 0.51 0.43 0.47 0.52
I221 0.38 0.34 0.37 0.51 0.32 0.56
I222 0.55 0.46 0.51 0.43 0.47 0.46
I223 0.43 0.44 0.36 0.43 0.32 0.30
I224 0.51 0.52 0.42 0.42 0.44 0.50
I225 0.45 0.46 0.43 0.44 0.45 0.48
I226 0.37 0.44 0.49 0.46 0.50 0.52
I227 0.49 0.57 0.56 0.39 0.47 0.59
I228 0.57 0.57 0.54 0.58 0.50 0.55
I229 0.48 0.61 0.58 0.58 0.51 0.54
I230 0.52 0.47 0.54 0.58 0.41 0.52
I231 0.48 0.57 0.61 0.55 0.57 0.65
I232 0.43 0.54 0.50 0.54 0.54 0.48
I233 0.39 0.38 0.44 0.48 0.61 0.55
平均 0.49 0.48 0.49 0.48 0.48 0.51

修正を加えて見れば、勝率は軒並み5割を切る結果になりました。ちなみにランダムで仕掛けを行った場合はきれいに5割あたりに落ち着きます。

銘柄間の分散測定

銘柄間で分散を計算します。前回と同じようにSMAとの比較を行います。

  • KAMA
Code Income Trades Win Pf Average DD
I201 4.65 78 28.21 1.03 0.06 -48.37
I202 -179.41 92 27.17 0.54 -1.95 -75.64
I203 -20.29 75 29.33 0.9 -0.27 -47.49
I204 -107.83 86 19.77 0.54 -1.25 -44.28
I205 -18.81 72 33.33 0.91 -0.26 -38.99
I206 -13.95 78 35.9 0.93 -0.18 -50.21
I207 44.76 65 32.31 1.25 0.69 -34.88
I208 8.01 74 33.78 1.06 0.11 -25.89
I209 -16.94 69 33.33 0.93 -0.25 -76.23
I210 -142.09 94 19.15 0.61 -1.51 -120.48
I211 92.4 55 30.91 1.55 1.68 -27.09
I212 -6.16 78 29.49 0.98 -0.08 -48.84
I213 33.61 61 31.15 1.15 0.55 -46.54
I214 -14.93 74 28.38 0.94 -0.2 -45.42
I215 11.94 71 28.17 1.05 0.17 -45.08
I216 27.79 70 32.86 1.13 0.4 -32.07
I217 79.23 74 32.43 1.39 1.07 -37.49
I218 -9.55 73 28.77 0.96 -0.13 -30.36
I219 -22.96 73 30.14 0.91 -0.31 -44.44
I220 47.13 72 33.33 1.26 0.65 -21.04
I221 -102.07 88 18.18 0.58 -1.16 -100.09
I222 100.2 66 28.79 1.39 1.52 -52.77
I223 -14.11 67 35.82 0.93 -0.21 -47.04
I224 -74.97 83 24.1 0.67 -0.9 -53.52
I225 -107.15 82 21.95 0.56 -1.31 -66.1
I226 -113.88 83 22.89 0.63 -1.37 -63.51
I227 0.24 71 29.58 1.0 0.0 -29.39
I228 -28.49 73 28.77 0.89 -0.39 -65.64
I229 202.88 62 38.71 1.79 3.27 -58.19
I230 -7.13 63 33.33 0.97 -0.11 -65.32
I231 83.78 59 40.68 1.4 1.42 -36.79
I232 27.17 65 29.23 1.11 0.42 -41.87
I233 18.6 71 30.99 1.13 0.26 -26.99
平均 -6.6 73.0 29.7 1.0 0.0 -49.9
偏差 75.22 9.0 5.14 0.29 1.02 20.83
  • SMA 6×36
Code Income Trades Win Pf Average DD
平均 -15.3 97.0 32.9 1.0 -0.1 -41.8
偏差 80.04 8.94 4.31 0.26 0.82 13.54

対して優位があるようには思えないですね。フィルターを使って騙しを消したほうがマシです。

損益分析

一応最も収益の良かったI222の損益分析をしてみましょう。

======================================================
net income:               100.20070429413443
profit | loss:            357.80826860451316    | -257.6075643103787
average:                  1.5181924893050671
pf:                       1.4
max profit | max loss:    68.22095385508365     | -16.4881192106323
trades | wins | looses:   66     | 19     | 47
wins{%}                   28.8
max series of wins:       3
max series of looses:     9
average span{win}:        82
average span{loose}:      19
max drow down:            -52.768023978241665
bunkrupt:                 0.0
======================================================
  • 損益曲線

profit_histgram

  • 損益ヒストグラム

profit_histgram

  • 月次損益

profit_histgram

だーめですね。

まとめ

2007年〜2017年の期間において、33業種別株価指数を用いて、KAMAを用いたシステムを検証しましたが、あまり良い結果は得られませんでした。

使えそうにありません。

このサイトはRubyでバックテストツールを作成し様々なストラテジーを検証することを目的としています。前回までは「売買システム入門」を読んでいましたが、今回からは「トレードシステムはどう作ればよいのか①」ジョージ・プルートを読み進めていきたいと思います。この本には具体的なストラテジーが紹介されていますので、それぞれ検証を行っていきましょう。

はじめに検証していくのはDBS(ダイナミック・ブレイクアウト・システム)を移動平均線による交差法に適用したシステムです。基本的にはSMAですが、ボラリティによって移動平均線の長さを変えていくシステムです。検証方法はこれまで同様に「売買システム入門」にて紹介されていた方法にて行おうと思います。

では見ていきましょう。

目次

実践

売買ルールの説明

● ボラティリティを標準偏差で表す>

1.昨日の終値から始まる過去20 日の終値の標準編差を計算する。

2.今日の終値から始まる過去20 日の終値の標準偏差を計算する。

3.昨日の終値から始まる過去30 日の終値の標準偏差を計算する。

4.今日の終値から始まる過去30 日の終値の標準偏差を計算する。

5.昨日と今日のボラティリティのデルタ(変動)を計算する(デルタ=[今日のボラティリティ-昨日のボラティリティ]÷ 今日のボラティリティ)。長期のボラティリティは標本集団が大きいため、短期のボラティリティに比べるとそれほど頻繁には変化しない。

● 2つの移動平均線を計算する

1.短期移動平均線は12 日からスタートする。

2.長期移動平均線は41 日からスタートする。

● 2つの移動平均の交差でトレードする

1.短期移動平均線が長期移動平均線を下から上に交差したら、翌日の寄り付きで買う。

2.短期移動平均線が長期移動平均線を上から下に交差したら、翌日の寄り付きで売る。

● 移動平均線の長さを調整する

1.現在の短期移動平均線の長さに(1+デルタ)を掛ける。

2.現在の長期移動平均線の長さに(1+デルタ)を掛ける。

3.短期移動平均線が長期移動平均線を下回り、2つの移動平均線を利益を生む範囲内に維持するために、次の制約を設ける必要がある。

● 短期移動平均線の長さ 最小で12 日 最大で23 日

● 長期移動平均線の長さ 最小で41 日 最大で50 日

● 移動平均線を新しい長さで計算しなおす

ジョージ・プルート『トレードシステムはどう作ればよいのか①』(PanRolling、2013年)

ボラが増えてるときは移動平均の長さを長くし、減ってるときは短くする。というルールでです。

ストラテジーの構築

コードはこのようになります。

class SmaDbs

    attr_accessor :length

    def initialize
      @length = 51
      @l_len = 41
      @s_len = 12
    end

    def set_env(soks, env)
      env[:closes] = Soks.parse(soks[0..-2],:close)
      env[:open] = soks[-1].open
    end

    def setup
      @l_len = 41
      @s_len = 12
    end

    def decide(env)
      code = env[:code]
      open = env[:open]
      date = env[:date]
      position = env[:position]
      closes = env[:closes]

      s_ave, l_ave = calc_ave(closes)

      if position
        if (s_ave[-1] > l_ave[-1]) and position.sell?
          return Action::Buy.new(code, date, open, 1)
        elsif (s_ave[-1] < l_ave[-1]) and position.buy?
          return Action::Sell.new(code, date, open, 1)
        else
          return Action::None.new(code,open)
        end
      end

      if s_ave[-1] > l_ave[-1]
        return Action::Buy.new(code, date, open, 1)
      elsif s_ave[-1] < l_ave[-1]
        return Action::Sell.new(code, date, open, 1)
      else
        return Action::None.new(code,open)
      end
    end

    def calc_ave(closes)
      l_dev = closes[-31..-1].dev(30)
      s_dev = closes[-21..-1].dev(20)

      l_delta = (l_dev[-1] - l_dev[-2]) / l_dev[-1]
      s_delta = (s_dev[-1] - s_dev[-2]) / s_dev[-1]

      @l_len *= (1 + l_delta)
      @l_len = [@l_len, 41].max
      @l_len = [@l_len, 50].min

      @s_len *= (1 + s_delta)
      @s_len = [@s_len, 12].max
      @s_len = [@s_len, 23].min

      l_ave = closes[-@l_len.to_i..-1].ave(@l_len.to_i)
      s_ave = closes[-@s_len.to_i..-1].ave(@s_len.to_i)
      [s_ave, l_ave]
    end
  end

チャートは23日と51日の移動平均を使っています。クロスの前に注文が入ってることは確認できるので、おおよそコードはこれで良いでしょう。なぜに51日かと言いますと、間違えたからです。

profit_histgram

N日検定

N日検定をかけます。勝率平均55%なんてのはまだ見たことがありませんがどうなりますかね。データは33業種別株価指数の2007年〜2017年を用います。そもそもトレンドフォロー系は勝率は低いもので、こんなもんなのかもしれませんね。

Code 5 10 15 20 30 50
I201 0.52 0.48 0.50 0.50 0.48 0.48
I202 0.49 0.51 0.51 0.53 0.50 0.42
I203 0.49 0.55 0.53 0.50 0.50 0.48
I204 0.53 0.48 0.54 0.44 0.46 0.52
I205 0.50 0.52 0.54 0.54 0.46 0.48
I206 0.49 0.48 0.50 0.47 0.53 0.46
I207 0.51 0.54 0.55 0.54 0.55 0.46
I208 0.49 0.47 0.51 0.48 0.49 0.42
I209 0.52 0.50 0.51 0.59 0.49 0.33
I210 0.48 0.47 0.47 0.48 0.43 0.42
I211 0.53 0.49 0.53 0.52 0.43 0.50
I212 0.52 0.45 0.47 0.46 0.39 0.44
I213 0.51 0.48 0.50 0.48 0.54 0.44
I214 0.52 0.55 0.54 0.51 0.49 0.44
I215 0.51 0.51 0.51 0.50 0.53 0.38
I216 0.50 0.54 0.51 0.47 0.51 0.50
I217 0.48 0.46 0.48 0.48 0.54 0.44
I218 0.48 0.49 0.47 0.40 0.41 0.48
I219 0.49 0.49 0.50 0.55 0.58 0.52
I220 0.49 0.47 0.47 0.55 0.51 0.60
I221 0.53 0.54 0.57 0.47 0.41 0.52
I222 0.49 0.49 0.50 0.51 0.50 0.60
I223 0.49 0.52 0.53 0.55 0.53 0.60
I224 0.44 0.43 0.45 0.45 0.43 0.44
I225 0.49 0.50 0.43 0.42 0.55 0.46
I226 0.50 0.50 0.49 0.50 0.53 0.42
I227 0.53 0.49 0.50 0.51 0.50 0.44
I228 0.49 0.46 0.45 0.47 0.45 0.29
I229 0.49 0.47 0.49 0.48 0.45 0.42
I230 0.50 0.52 0.56 0.51 0.49 0.42
I231 0.48 0.51 0.48 0.46 0.51 0.40
I232 0.47 0.49 0.46 0.48 0.50 0.42
I233 0.53 0.53 0.48 0.53 0.49 0.48
平均 0.50 0.50 0.50 0.50 0.49 0.46

銘柄間の分散測定

銘柄間で分散を計算します。分散が小さければより堅牢なシステムだと言えるとのことですが、まぁどのあたりかって明確な基準は知らないので、他のシステムとの比較が必要になるのでしょうね。この場合だとSMAですか。

  • SMA DBS
Code Income Trades Win Pf Average DD
I201 25.87 77 38.96 1.15 0.34 -38.24
I202 40.87 72 44.44 1.16 0.57 -40.17
I203 -32.74 64 35.94 0.84 -0.51 -33.29
I204 -66.5 90 33.33 0.67 -0.74 -33.17
I205 -13.04 77 33.77 0.93 -0.17 -37.54
I206 -160.72 73 32.88 0.49 -2.2 -57.85
I207 4.35 74 31.08 1.02 0.06 -43.01
I208 -71.15 79 24.05 0.63 -0.9 -32.1
I209 51.36 62 41.94 1.25 0.83 -58.35
I210 -23.59 78 33.33 0.92 -0.3 -95.9
I211 23.07 66 33.33 1.1 0.35 -38.98
I212 5.27 73 43.84 1.02 0.07 -54.05
I213 40.23 63 38.1 1.17 0.64 -48.16
I214 63.09 58 37.93 1.4 1.09 -37.64
I215 35.82 62 29.03 1.15 0.58 -35.47
I216 -10.36 72 37.5 0.96 -0.14 -43.33
I217 4.75 73 31.51 1.02 0.07 -41.97
I218 -0.01 70 37.14 1.0 0.0 -29.44
I219 -36.41 71 42.25 0.86 -0.51 -47.68
I220 27.68 75 40.0 1.15 0.37 -41.04
I221 2.61 67 34.33 1.02 0.04 -31.63
I222 120.67 64 42.19 1.53 1.89 -42.13
I223 -17.78 67 35.82 0.91 -0.27 -35.74
I224 -128.11 87 27.59 0.54 -1.47 -65.44
I225 -33.1 75 32.0 0.81 -0.44 -26.09
I226 -69.11 66 33.33 0.73 -1.05 -45.58
I227 -11.65 73 39.73 0.93 -0.16 -33.85
I228 -30.5 76 36.84 0.89 -0.4 -51.67
I229 34.2 66 30.3 1.09 0.52 -69.08
I230 -8.02 62 35.48 0.97 -0.13 -48.11
I231 -50.11 66 37.88 0.83 -0.76 -53.68
I232 -28.32 71 32.39 0.91 -0.4 -65.12
I233 39.9 71 42.25 1.29 0.56 -31.1
平均 -8.2 70.0 35.8 1.0 -0.1 -45.0
偏差 53.35 7.0 4.77 0.22 0.75 14.07
  • SMA 23×51
Code Income Trades Win Pf Average DD
平均 2.1 54.0 35.5 1.0 0.1 -41.6
偏差 58.73 5.48 5.59 0.3 1.06 13.11

23日と51日のゴールデンクロス、デッドクロスでの売買を行ったほうが成績は微妙に良さそうですね。

損益分析

一応最も収益の良かったI214の損益分析をしてみましょう。

======================================================
net income:               63.089022560403215
profit | loss:            221.25246116662524    | -158.16343860622192
average:                  1.087741768282814
pf:                       1.4
max profit | max loss:    37.25461513706445     | -10.241653639739926
trades | wins | looses:   58     | 22     | 36
wins{%}                   37.9
max series of wins:       4
max series of looses:     8
average span{win}:        76
average span{loose}:      20
max drow down:            -37.636184966997675
bunkrupt:                 0.0
======================================================
  • 損益曲線

profit_histgram

  • 損益ヒストグラム

profit_histgram

  • 月次損益

profit_histgram

だめですね。

まとめ

2007年〜2017年の期間において、33業種別株価指数を用いて、DBSを適用したSMAシステムを検証しましたが、DBSを適用しないほうが僅かに収益は出るという結果に終わりました。

使えそうにはありません。

ただ、偏差の増減によって長さを変えてみようって考えは意味があるのかはさておき面白かったです。本当に僅かな可能性の中から試行錯誤してシステムを作っていく上で、なんか試してみようってのは必要ですよね。

「売買システム入門」を読み進めてきましたが、今回で最後としたいと思います。最後に取り上げるのはデータスクランブル、疑似データを用いた検証方法についてです。

疑似データは過去の日足をランダムピックしながら作るものです。まず作成方法について説明します。次に33業種別株価指数の幅広い銘柄において十分に有効だと思われる自作のシステムを紹介します。そして疑似データを用いてバックテストを行った場合にどうなるかってのを調べていきたいと思います。

早速参りましょう。

目次

実践

目次1

疑似データは下記の手順で作るとあります。

2本の日足を隣り合わせにする。そして1本目の日足の終値を基準として、2本目の日足の始値(0)、高値(H)、安値(L)、終値(C)との関係について調べる。この関係は以下のように示される。

delta O = O - C[1],

delta H = H - C[1],

delta L = L - C[1],

delta C = C - C[1]. 

ここで表れている[1]の記号は前日を意味する。

新たな日足は以下のように前日終値から導き出される(新たに作成した擬似データにはSynという接頭語を使っている)。

Syn - Close = Close[1] + delta C,

Syn - High = Close[1] + delta H,

Syn - Low = Close[1] + delta L,

Syn - Open = Close[1] + delta O.

トゥーシャー・シャンデ『売買システム入門』(PanRolling、2000年)

これだと高い時の株価と安い時の株価で価格差が異なることが考慮できてないですね。せめて前日比、または対数を取るべきでだと思うので、ここでは前日比を用いて疑似データの作成をしていきます。ただしデータは少数になるので、ティックを用いたストラテジーを検証することはできなくなります。

計算は次のようになります。初値のみ表示しますが、他についても同様です。

  • delta O = O / C[1]
  • Syn - O = Close[1] * delta O

コードは次のようになります。後半はチャートをプロットするためのコードです。

Bundler.require
include Kabu

n = 3000
com = Company.find_by_code 'I201'
file = File.expand_path "../../../data/strategy1-5/chart/#{com.code}.jpeg", File.dirname(__FILE__)

soks = com.soks
diffs = Soks.new
shuffled = Soks.new

soks.each_cons(2) do |prev,curnt|
  pc = prev.close
  diffs << [curnt.open/pc, curnt.high/pc, curnt.low/pc, curnt.close/pc]
end

shuffled << soks[-1]
(n-1).times do
  i = Random.rand(soks.length-1)
  pc = shuffled[-1].close
  s = Sok.new
  s.open = diffs[i][0] * pc
  s.high = diffs[i][1] * pc
  s.low = diffs[i][2] * pc
  s.close = diffs[i][3] * pc
  shuffled << s
end

values = Kabu::Soks.parse(shuffled,:open,:high,:low,:close)
up_stick, down_stick = values.split_up_and_down_sticks

Numo.gnuplot do
  reset
  set terminal: 'jpeg'
  set output:  file
  set grid: true
  plot [n.times.to_a, *up_stick.y, with: :candlesticks, lt: 6, notitle: true],
    [n.times.to_a, *down_stick.y, with: :candlesticks, lt: 7, notitle: true]
end

描画したチャートはこんな感じになりました。なかなかそれっぽいチャートが仕上がります。

profit_histgram

MMSシステムのパフォーマンス

著書のシステムはあまりパフォーマンスがよろしくないので、33業種別株価指数の多くの銘柄で有効だと思われるシステムを用意しました。ルールはこんな感じになります。

バグですな。。。Gainの取得が当日終値を使用しているため、未来のデータを用いています。2017/5/31追記

  • 仕掛け
    • 終値の前日比の65日偏差を超える前日比が発生した翌日の初値
  • ロスカット
    • 終値が前日比-1%となった翌日の初値
  • 仕切り
    1. 終値で利益が20%出た翌日の初値で仕切り
    2. 終値で利益が10%出ていてかつ仕掛けのルールを満たした場合翌日の初値でドテン
    3. 終値で利益が2%出ていてかつ25日ボリバン2.0を抜けていた翌日の初値で仕切り

この辺の数字は比較的適当に選んだ数字で最適化は言うほど行っておりません。これとは別のいくつかの仕掛けをN日検定にかけてみましたが、平均で勝率55%を達成するという優位な結果を得ることができなかったため、仕掛けをわやくちゃすることを諦めました。たまたま持ってしまったポジションが悪けりゃ即切って、良ければ出来る限り利益が出ているときに切る、そんな感じに動くシステムです。

コードはこのようになります。

module Kabu
  class TestStrategy

    attr_accessor :length, :n

    def initialize
      @length = 67
    end

    def set_env(soks, env)
      env[:soks] = soks
    end

    def setup
    end

    def decide(env)
      soks = env[:soks]
      code = env[:code]
      date = env[:date]
      position = env[:position]
      closes = Soks.parse(soks,:close)

      log = closes[-67..-2].log
      ave,btm,top,dev = log.bol(65,1)
      if not position.nil?

        gain = position.gain(soks[-1].close,1)

        if gain > 20 or gain < -1
          if  position.sell?
            return Action::Buy.new(code,date,soks[-1].open,1)
          elsif position.buy?
            return Action::Sell.new(code,date,soks[-1].open,1)
          end
        end

        if gain > 10
          if log[-1] < btm[-1] and position.sell?
            return Action::Buy.new(code,date,soks[-1].open,2)
          elsif log[-1] > top[-1] and position.buy?
            return Action::Sell.new(code,date,soks[-1].open,2)
          end
        end

        if gain > 2
          bol = closes[-26..-2].bol(25,2.0)

          if bol[1][-1] > closes[-2] and position.sell?
            return Action::Buy.new(code,date,soks[-1].open,1)
          elsif bol[2][-1] < closes[-2] and position.buy?
            return Action::Sell.new(code,date,soks[-1].open,1)
          end
        end

        return Action::None.new(code,soks[-1].open)
      end

      if log[-1] < btm[-1]
        return Action::Buy.new(code,date,soks[-1].open,1)
      elsif log[-1] > top[-1]
        return Action::Sell.new(code,date,soks[-1].open,1)
      else
        return Action::None.new(code,soks[-1].open)
      end
    end
  end
end

仕切りのルールを取っ払って、N日検定をした結果はこんな感じです。2007年から2017年の期間で33業種別株価指数を使い検定を行っています。仕切り日のN日には5、10、15、20、30、50を使いました。

Code 5 10 15 20 30 50
I201 0.54 0.53 0.50 0.53 0.61 0.53
I202 0.53 0.51 0.58 0.58 0.44 0.59
I203 0.51 0.49 0.55 0.53 0.56 0.49
I204 0.53 0.49 0.56 0.55 0.54 0.51
I205 0.48 0.49 0.49 0.56 0.51 0.58
I206 0.48 0.47 0.55 0.57 0.51 0.49
I207 0.54 0.54 0.54 0.50 0.54 0.53
I208 0.50 0.49 0.48 0.46 0.42 0.44
I209 0.53 0.51 0.42 0.49 0.59 0.54
I210 0.48 0.48 0.47 0.43 0.36 0.53
I211 0.49 0.53 0.55 0.56 0.54 0.51
I212 0.50 0.54 0.48 0.52 0.45 0.51
I213 0.52 0.48 0.56 0.54 0.53 0.56
I214 0.47 0.46 0.51 0.49 0.41 0.48
I215 0.53 0.46 0.53 0.50 0.48 0.47
I216 0.53 0.48 0.44 0.52 0.48 0.40
I217 0.53 0.55 0.50 0.53 0.58 0.51
I218 0.52 0.48 0.50 0.49 0.52 0.53
I219 0.48 0.54 0.47 0.51 0.52 0.44
I220 0.51 0.52 0.51 0.45 0.58 0.51
I221 0.53 0.49 0.60 0.58 0.56 0.52
I222 0.53 0.47 0.50 0.48 0.57 0.56
I223 0.50 0.52 0.54 0.54 0.50 0.42
I224 0.46 0.49 0.49 0.47 0.58 0.64
I225 0.51 0.56 0.53 0.53 0.50 0.57
I226 0.51 0.48 0.47 0.46 0.58 0.60
I227 0.49 0.43 0.52 0.47 0.46 0.47
I228 0.50 0.54 0.49 0.47 0.64 0.46
I229 0.49 0.49 0.52 0.55 0.49 0.41
I230 0.49 0.46 0.47 0.56 0.49 0.49
I231 0.50 0.51 0.53 0.41 0.46 0.28
I232 0.52 0.47 0.51 0.49 0.42 0.46
I233 0.52 0.58 0.58 0.56 0.54 0.36
平均 0.51 0.50 0.51 0.51 0.51 0.50

55%を超えることが仕掛けルールの優位を示唆する基準となっていますが、どのN日においてもせいぜい51%ですので、このシステムに仕掛けの優位はあまり期待できません。

続いて、同じ期間同じ銘柄を使って銘柄間の平均収益などを見ていきます。ここからは、先に提示したルール、コードを用います。

Code Income Trades Win Pf Average DD
I201 203.12 211 40.76 2.24 0.96 -10.12
I202 364.62 288 39.24 2.06 1.27 -27.58
I203 175.82 235 34.89 1.91 0.75 -14.0
I204 146.41 193 32.64 1.92 0.76 -17.82
I205 152.7 245 34.69 1.77 0.62 -11.16
I206 300.53 259 42.86 2.42 1.16 -14.48
I207 238.65 218 33.94 2.23 1.09 -19.91
I208 172.16 196 38.27 2.16 0.88 -13.72
I209 281.27 243 37.45 2.15 1.16 -13.69
I210 329.29 267 41.2 2.18 1.23 -18.8
I211 301.33 248 37.5 2.3 1.22 -12.26
I212 163.57 317 32.49 1.41 0.52 -23.01
I213 255.28 261 36.4 1.87 0.98 -18.08
I214 166.3 241 32.78 1.72 0.69 -20.83
I215 243.91 252 35.32 1.98 0.97 -30.73
I216 204.72 249 32.13 1.77 0.82 -25.28
I217 143.27 245 33.06 1.49 0.58 -21.18
I218 343.36 239 41.42 2.61 1.44 -13.7
I219 203.49 270 33.7 1.7 0.75 -23.97
I220 256.14 222 42.34 2.43 1.15 -13.14
I221 130.02 203 32.02 1.81 0.64 -17.0
I222 443.44 308 42.53 2.33 1.44 -19.29
I223 210.12 229 37.99 2.15 0.92 -13.18
I224 176.55 236 34.32 1.78 0.75 -18.64
I225 272.41 220 35.91 2.74 1.24 -9.62
I226 248.62 246 37.4 2.02 1.01 -16.97
I227 148.64 220 33.18 1.77 0.68 -11.66
I228 36.1 279 31.9 1.11 0.13 -33.02
I229 246.93 316 37.03 1.57 0.78 -21.25
I230 285.37 305 38.03 1.81 0.94 -24.58
I231 197.37 301 36.21 1.52 0.66 -23.47
I232 345.68 270 43.33 2.15 1.28 -21.66
I233 158.13 194 29.9 2.02 0.82 -21.83
平均 228.6 249.0 36.4 2.0 0.9 -18.7
偏差 81.74 34.47 3.65 0.35 0.29 5.77

業種間平均で200%を超える結果を残せています。年利20%!なかなかですね。最大ドローダウンは平均約20%。1%で損切りのシステムですので、負けがかさむのと、翌日仕切りのためのスリップによる影響が考えられます。

このバックテストは取引コストを勘定していません。成り行き売買で往復2ティック0.1%、SMBCなどの金利だけで取引できるところを選んで金利0.1%程度を見込んでも、0.9%の平均収益がありますので、十分プラスが出ると期待できます。

一番収益を上げたI202 について分析してみます。前回触れた破産確率も表示してみましょう。

======================================================
net income:               364.6153239672717
profit | loss:            707.2600967847432    | -342.6447728174714
average:                  1.2660254304419156
pf:                       2.1
max profit | max loss:    20.01936577099975     | -11.377274254716523
trades | wins | looses:   288     | 113     | 175
wins{%}                   39.2
max series of wins:       7
max series of looses:     10
average span{win}:        10
average span{loose}:      3
max drow down:            -27.58244976567554
bunkrupt:                 0.0
======================================================

破産確率は0%ですね。 素晴らしいじゃないですか。自画自賛。 ちなみにこの破産確率は、資金投下率100%つまり、レバレッジはかけずにトレードを1000回行った間に破産する確率をシミュレーションによって求めています。

  • 損益曲線

profit_histgram

  • 損益ヒストグラム

profit_histgram

  • 月次収益

profit_histgram

一見うなぎのぼりな損益曲線ですが、月次で見てみると4ヶ月もの間マイナスを漂う可能性があると事前に知っていることは有益だと思います。

一番成績の悪かったI228も見てみましょう。

======================================================
net income:               36.09507890151175
profit | loss:            377.1703053400553    | -341.0752264385436
average:                  0.1293730426577482
pf:                       1.1
max profit | max loss:    15.05757858699035     | -12.36803302860513
trades | wins | looses:   279     | 89     | 190
wins{%}                   31.9
max series of wins:       4
max series of looses:     11
average span{win}:        8
average span{loose}:      4
max drow down:            -33.016308846121134
bunkrupt:                 0.0
======================================================

これでも破産確率は0%です。

  • 損益曲線

profit_histgram

  • 損益ヒストグラム

profit_histgram

  • 月次収益

profit_histgram

プラスが出てるとはいえ、しんどいグラフですね。ヒストグラムを見ると、2%〜5%にかけて谷ができているので、ボリバンを使った仕切りルールに銘柄依存があると示唆されます。

さて、このシステムを擬似データを使ってバックテストした場合どうなるか?気になりませんか?

疑似データを用いた検証

著書には、疑似データはトレーダーの心理を反映していないため、あくまで平均がどうなるかが重要だとあります。

疑似データ約60年分(12000本)を作成しバックテストを行い、10回それを行った時の平均を求めてみましょう。オリジナルのデータにはI201の2007年から2017年のものを使用します。

結果は次のようになりました。

Code Income Trades Win Pf Average DD
0 910.27 1020 36.67 2.19 0.89 -16.96
1 952.62 1073 35.88 2.18 0.89 -14.27
2 1060.83 1064 38.63 2.38 1.0 -15.14
3 1125.88 1079 38.37 2.43 1.04 -13.1
4 1086.83 1038 35.55 2.4 1.05 -16.1
5 865.8 1079 36.14 2.06 0.8 -15.42
6 1179.46 1080 38.7 2.48 1.09 -16.7
7 1172.92 1032 39.24 2.59 1.14 -14.6
8 963.13 1084 37.18 2.14 0.89 -20.25
9 968.94 1016 37.5 2.26 0.95 -23.36
平均 1028.7 1056.0 37.4 2.3 1.0 -16.6
偏差 105.64 25.61 1.24 0.16 0.1 2.91

これは十分に期待できる結果じゃないでしょうか?コードに間違いがあるのじゃないかと不安になります。

まとめ

疑似データを作成して、バックテストを行う方法について説明しました。実際に期待できるシステムを用いてバックテストを行い、十分に期待が出来ることについて確認を行いました。実際にはシステムに穴があることを確認するための手順ですが、このシステムは十分に堅牢であると言えると思います。

私はかなり長い間こういったシストレ本に懐疑的でした。ですが、実際に丁寧に読んでみるとかなり収穫があることがわかりました。10年前に出会いたかったです。

売買システム入門を読み進めています。この本に挙げられている検証方法でシステムを検証していくと、一体システムトレードのどこに優位性があるのか訝しくなります。

では、この本が読む価値がないかと問われると、そうは思いません。なぜならばシステムの評価方法について、いくつかの方法を提示してくれるからです。タイトルは考え方→作成→評価となっていて、たしかに信条を説明しモデルを提示しているのですが、正直私はその辺は魅力を感じません。評価においてこの本は読む価値があると思います。実際に、この本を読み進めるだけで、私はシステムに対する評価方法をいくつか手に入れることができました。これは大きいと思います。

今回は破産確率という点でシステムを評価しましょう。破産確率はバルサラの破産確率が有名ですが、ここではシミュレーションを行って、1000回の試行で破産する確率を求め、破産確率に対するレバレッジの効果について調べていきます。

目次

実践

破産確率を求めるには

著書にはノーザー・バルサラ氏の著書を参考にし、シミュレーションを行ったとあります。このバルサラの破産確率というのは、至るブログで紹介されていて、その上ほとんどのブログの表は間違いだなどと指摘されていたりなど、何が正しいのか原著を読むしかない状況となっています。しかし、この原著が高いんですね。みんな読まないので好き放題出来るのでしょう。地雷はスルーします。

シャンデ氏の著書では1000回の試行で破産する確率をシミュレーションによって求めたとありますので、私もそうしたいと思います。用いる変数は著書と同じように下記になります。

  • ペイオフ比率(平均利益率 / 平均損失率)
  • 勝率
  • 許容リスク(投下資金比率 * 平均損失率)

シミュレーション方法

シミュレーションの流れはこんなものです。

  1. 乱数を用いて勝敗を決定
  2. 勝った場合: 許容リスク*ペイオフ比率を取得
  3. 負けた場合: 許容リスクを失う
  4. 1000回の試行までに全資金を失った場合破産

コードはこのようになります。

    def simulate
      bunkrupt_times = 0
      n.times do
        capital = 1
        bunkrupt = false
        span.times do
          gain = (Random.rand <= @win ? @pf * @risk  : - @risk)
          capital += gain
          if capital < 0
            bunkrupt = true
            break
          end
        end
        bunkrupt_times += 1 if bunkrupt
      end
      bunkrupt_times.to_f / n * 100
    end

破産確率

これを各々のパラメータについて1000回繰り返して破産した確率を求めます。 1%、1.5%、2%の許容リスクの場合、結果はこのようになります。

  • 1%
  1.0 1.5 2.0 2.5 3.0
25 100.0 100.0 100.0 76.0 5.1
30 100.0 100.0 61.5 0.3 0.0
35 100.0 78.7 0.2 0.0 0.0
40 100.0 0.7 0.0 0.0 0.0
45 55.8 0.0 0.0 0.0 0.0
50 0.2 0.0 0.0 0.0 0.0
  • 1.5%
  1.0 1.5 2.0 2.5 3.0
25 100.0 100.0 100.0 93.3 23.7
30 100.0 100.0 84.2 4.5 0.0
35 100.0 96.5 1.7 0.0 0.0
40 100.0 8.8 0.0 0.0 0.0
45 88.3 0.0 0.0 0.0 0.0
50 3.3 0.0 0.0 0.0 0.0
  • 2%
  1.0 1.5 2.0 2.5 3.0
25 100.0 100.0 100.0 96.4 35.3
30 100.0 100.0 92.7 9.0 0.1
35 100.0 99.4 4.9 0.0 0.0
40 100.0 18.7 0.0 0.0 0.0
45 96.4 0.0 0.0 0.0 0.0
50 10.7 0.0 0.0 0.0 0.0

シャンデ氏の著書と若干のブレはありますが、いい値を吐き出しているようです。

許容リスクを上げたということは、例えばあなたが平均損失率1%のシステムを使っていたとすると、レバレッジをかけて1.5倍、2倍の資金を投入したことに対応します。こうした時、よほど優秀なシステムでなければ多くの場合破産する可能性があることがわかると思います。

なお、ここで示している破産確率は、提示した方法で計算した場合の破産確率であり、また十分に収束していないため、周りに溢れている確率表とは一致しません。

まとめ

破産確率をシミュレーションによって求めました。レバレッジをかけた場合、多くのシステムが1000回のトレードのうちに破産する可能性があることを示しました。

Recent Entries
Categories
    Tags
    Archives
    Search