システム検証

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

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

今回は破産確率という点でシステムを評価しましょう。破産確率はバルサラの破産確率が有名ですが、ここではシミュレーションを行って、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回のトレードのうちに破産する可能性があることを示しました。

前回に引き続き、「売買システム入門」に従い、SMA65CC3を使ってストラテジーの検証を行っていきます。

ところで皆さんはロスカットをどうやって設定していますか?仕掛けの有効性はN日検定を用いることで調べることが出来ると記されていることを前回紹介しました。売買システム入門にはロスカットの評価方法についても詳細に説明されています。今回はその辺について紹介していきたいと思います。

目次

ロスカットを追加する理由

バックテストを行っていると、最終収益はいいけども果たしてこのシステムは別のシステムに勝っているのか?と疑問になることが多々有ると思います。特にロスカットの設定は、追加することで利益が減ることが多いため、それなら追加しないほうが良いのか?などと考えることも有るかもしれません。

シャンデ氏はトレーディングシステムの基本原則なるものを6つほど上げていまして、その一つにこのようにあります。

3.トレーディング・システムのパラメータの数値は堅牢なものでなければならない。要するに様々な時間枠、多くの異なるマーケットで機能する必要がある。

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

そして、ロスカットの追加がこの堅牢性を高めているってことが幾つかのデータを使って提示されています。著書に習って検証を行って行きたいと思います。

MFEの調査

MFEとは最高到達地点と呼ばれるもので、ポジションを持っているときに経験した最大の含み益や含み損のことを言うようです。ちなみに、なんの略かは記されていなのでわかりません。そこまで翻訳してほしいものです。

このMFEを調べることでロスカットのどこに置くべきか当たりをつけることが出来るようになります。早速調べてみましょう。

前回と同じように33業種別株価指数を用いて検証を行いますが、前回は円ベースで集計を行っていたため、銘柄間の比較を行うことができませんでした。そこで今回は収益をパーセントで集計するように回収を加え、銘柄間の比較がもうちょっとマシな形で出来るようにさせています。ストラテジーも同じものを使います。まだロスカットルールは追加しません。

勝ちトレードの最大含み損と負けトレードの最大含み益を集計してヒストグラムにすると、下記のようになりました。

  • 勝ちトレードのMFE

profit_histgram

  • 負けトレードのMFE

profit_histgram

Y軸が対数なんで、ぱっと見線形ですが気をつけてください。

これを見ると、勝ちトレードの大半は1% の含み損しか経験しておらず、負けトレードの中には20%もの含み益を持っていたものがある、などということが解ると思います。

勝ちトレードのMFEを累積させて表示させてみます。最大値は勝ちトレード数になりますので、そこを100とします。

profit_histgram

こうしてみると、例えば-4%当たりにロスカットラインを設定したとしても、残りの9割の勝ちトレードには影響を与えないことがわかります。これは有益な情報でですね。

ストラテジーの構築

ここで行いたいのは、ストップロスを使用しなかった最初のシミュレーションと全く同じトレードについて検証することである。この目的を達成するためには、同じシグナルが続くことを避けるためのルールを設定し、最初のシグナルで損切りを余儀なくされた後に再び同じ方向のトレードが続かないようにすることである。

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

ということですので、これをコーディングしていきます。Ifが深くなるので、ネストを浅くしときます。

class Sma65Cc3StopLoss

  def initialize(loss_line)
    @loss_line = loss_line
    @loss_cut = false
  end

  def reset
    @loss_cutted = false
    @last_position = nil
  end

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

    aves = closes[-67..-1].ave(65)
    is_buy = 3.times.inject(true) do |ret, i|
      ret = (ret and (closes[-1-i] > aves[-i-1]))
    end

    is_sell = 3.times.inject(true) do |ret, i|
      ret = (ret and (closes[-1-i] < aves[-i-1]))
    end

    if position.nil? and not @loss_cutted
      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

    if position.nil? and @loss_cutted
      if  @last_position.buy? and is_sell
        reset
        return Action::Sell.new(code,date,open,1)
      elsif @last_position.sell? and is_buy
        reset
        return Action::Buy.new(code,date,open,1)
      else
        return Action::None.new(code,open)
      end
    end

    is_loss_cut = position.gain(closes[-1],1) < @loss_line

    if is_loss_cut
      @loss_cutted = true
      @last_position = position
      if position.buy?
        return Action::Sell.new(code,date,open,1)
      elsif position.sell?
        return Action::Buy.new(code,date,open,1)
      end
    end

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

必要に応じてgit pullしてください。

ロスカットの効果

では、実際にロスカットラインを-10%〜-1%に設定させながら、バックテストを行い、結果にどのような影響を及ぼすのかを見てみましょう。2007年〜2017年の33業種別株価指数を用いて、バックテストを行い、銘柄間で平均した収益と、最大ドローダウンをロスカットラインに対して表示してみます。ただし-11%のデータはロスカットを設定しなかった場合の値です。

profit_histgram

ロスカットラインが狭くなるに連れて収益とドローダウンが減少しているのが見て取れます。この辺は予想通りでしょう。

続いて、銘柄間の偏差を見てみます。

profit_histgram

ロスカットラインが狭くなると、偏差も減少していることがわかります。つまり、銘柄間のバラ付きが少なくなったということです。この辺がシステムの堅牢性の話につながるのでしょう。

勝ちトレード数はもちろん減少しますが、平均値はどうでしょうか?

profit_histgram

悪化していますね。 ここまでの検証はexample/back_test/strategy1-2/にコードがあります。

まとめ

SMA65CC3にロスカットルールを加えました。すると、収益や平均収益が減少しました。悲しい限りです。

一方で最大ドローダウンが減少し、銘柄間の偏差も減少することがわかりました。つまり、システムが堅牢になったといえます。そもそもマイナス収益ですが。

システムの堅牢性に対する認識の差が、どのシステムを良しとするかの分かれ目になりそうですね。

次回も引き続き「売買システム入門」を読み進めて行きます。次回は騙しシグナルのフィルタリングの効果について検証していきます。

AndroidのアプリにTermuxというLinuxターミナルエミュレータが有るのですが、それを使ってツールが動かないかなと試行錯誤してみたら、無事に動かせるってことがわかりました。./configure make make installとか久しぶりでした。

このツールが動くってことはnokogiriとsqlite3が動くってことなのでRails動くかなと思いましたが、インストールできても起動に失敗するようです。また機会があったら挑戦してみようと思います。

さて、このサイトはRubyでバックテストツールを作成し様々なストラテジーを検証することを目的としています。前回はSMA65CC3ストラテジーにロスカットルールを追加しました。そこでパフォーマンスの悪化は見られるものの、システムが堅牢となることを示しました。今回も引き続き「売買システム入門」を読み進め、SMA65CC3の改良を行っていきます。

今回はRAVI指標を用いてシグナルのフィルタリングを行います。今までマイナスを履き続けるシステムでしたが、このフィルターによってようやくプラスを吐き出すことに成功しました。最も使えるかは別ですが。

早速見ていきましょう。

目次

RAVI指標とは

RAVI指標とは、レンジアクション・ベリフィケーション・インデックスの略で、レンジ内で推移する状態に焦点を絞った指標であり、当日の値動きが前日の値動き幅をどの程度上回っているかをみるものになります。

<RAVI指標の計算方法>

RAVI=(短期移動平均-長期移動平均)÷長期移動平均×100

RAVI指標が、基準値を下回った場合には、マーケットはレンジ内での推移と判断し、これ以上の場合はトレンドが現れている事を意味するという使い方をします。

「超早分かり!テクニカル分析」

実際にチャートを見てみましょう。下段がRAVIです。仮に1%を基準値とした場合 、トレンドがないと判断した日足の色を変えています。

ravi

前半はトレンドに勢いがあって、RAVIも吹っ切れていますが、後半はヨコヨコ展開になり、1%を下回る日がちらほらとあります。SMA65CC3によって発生する無駄なシグナルをいくつか消せそうなのが見て取れると思います。

ストラテジーの構築

フィルターの効果を検証するため、前回のロスカットルールは追加しません。またRAVIでシグナルをキャンセルした場合、一旦平均線を逆にクロスするまでは注文をかけないようにします。コードは下記のようになります。

module Kabu
  class Sma65Cc3Ravi

    def initialize(line = 1)
      @line = line
    end

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

      ravi = closes.ravi(7,65)
      return Action::None.new(code,open) if ravi[-1] < @line

      aves = closes[-68..-1].ave(65)
      is_buy = 3.times.inject(true) do |ret, i|
        ret = (ret and (closes[-1-i] > aves[-i-1]))
      end
      is_buy = (is_buy and (closes[-4] <= aves[-4]))

      is_sell = 3.times.inject(true) do |ret, i|
        ret = (ret and (closes[-1-i] < aves[-i-1]))
      end
      is_sell = (is_sell and (closes[-4] >= aves[-4]))

      if position.nil?
        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

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

検証

2007年〜2017年の33業種別株価指数を用いてバックテストを行ってみましょう。フィルターをかけない場合についてもバックテストして集計結果を比較してみます。

code net income trades win pf average dd
I201 45.29 23 47.83 1.61 1.97 -25.88
I202 12.68 45 42.22 1.07 0.28 -51.85
I203 -71.65 29 20.69 0.55 -2.47 -86.99
I204 -60.81 35 17.14 0.61 -1.74 -41.94
I205 85.88 19 36.84 2.33 4.52 -42.7
I206 15.59 44 31.82 1.11 0.35 -30.76
I207 102.95 31 35.48 2.12 3.32 -24.27
I208 49.18 26 38.46 1.68 1.89 -23.01
I209 120.83 31 51.61 2.44 3.9 -18.23
I210 9.81 49 26.53 1.06 0.2 -71.19
I211 -69.45 42 35.71 0.69 -1.65 -86.34
I212 -6.44 36 30.56 0.97 -0.18 -66.37
I213 -108.57 29 37.93 0.52 -3.74 -76.68
I214 53.21 27 44.44 1.5 1.97 -34.81
I215 68.02 36 33.33 1.5 1.89 -47.18
I216 88.26 25 32.0 1.84 3.53 -31.32
I217 161.7 25 48.0 3.22 6.47 -26.91
I218 45.03 25 32.0 1.38 1.8 -42.0
I219 -174.23 29 31.03 0.31 -6.01 -112.65
I220 101.79 20 50.0 2.45 5.09 -29.03
I221 50.24 21 38.1 1.65 2.39 -33.73
I222 85.85 30 46.67 1.55 2.86 -59.79
I223 107.13 26 46.15 2.26 4.12 -28.91
I224 -139.4 28 21.43 0.28 -4.98 -130.13
I225 20.9 26 34.62 1.19 0.8 -79.6
I226 -46.69 37 32.43 0.73 -1.26 -46.47
I227 -64.09 26 23.08 0.52 -2.46 -74.03
I228 -36.1 34 41.18 0.81 -1.06 -60.87
I229 173.81 38 26.32 1.83 4.57 -61.75
I230 41.08 33 36.36 1.27 1.24 -69.13
I231 83.14 34 41.18 1.57 2.45 -64.67
I232 107.23 38 34.21 1.77 2.82 -48.75
I233 63.45 17 47.06 2.06 3.73 -20.73
平均 27.7 30.0 36.1 1.4 1.1 -53.0
偏差 82.56 7.62 8.74 0.7 2.92 26.53
平均/無 -13.4 69.0 26.3 1.0 -0.1 -47.9
偏差/無 67.06 8.66 4.79 0.27 0.94 16.36

なんということでしょう。全く稼げなかったあのシステムが、わずかばかりか稼げるようになりました。PFの業種間平均は1.4。平均収益の平均は1.1%。そうはいっても、ここから取引コストを勘定することを考えれば、まだまだ使い物にはなりませんね。

著書には、フィルターについてはあまり多く触れられていません。RAVIのラインを切り下げた場合についての比較程度となっています。この辺はカーブフィッティングにつながりやすいからかもしれませんね。ですので、さっぱりとしていますが今回はこれで終わりです。

まとめ

RAVIを使ってシグナルにフィルターをかけました。すると収益が改善することがわかりました。

次回はSMA65CC3システムについてはこれで終わりにして、シャンデ氏の著書に紹介されている次のシステムの検証に入りたいと思います。

このサイトはRubyでバックテストツールを作成し様々なストラテジーを検証することを目的としています。前回まではSMA65CC3についての検証を行っていました。その中でシステムを、N日検定とMFEを用いた方法で評価しました。

今回も引き続きこちらの本を読み進めていきます。

今回はSMA65CC3システムの次に紹介されているCB-PBシステムについて検証を行っていきます。特にこの章では仕切りルールに対して焦点が当てられているので、それに習って2パターンの仕切りルールを検証していきたいと思います。 それでは参りましょう。

目次

CB-PBシステムとは

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

20日の新高値を付けた後の下落局面で買いポジションを建てる買いシグナルのみのシステムをチャネル・ブレイクアウト-プルバック(CB-PB)システムと呼ぶ。

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

ブレイクアウトシステムに似ていますが、ブレイクアウトしてからの戻しで買おうってシステムのようですね。

戻しといっても色々な定義の仕方があります。ここでは、このようにすることにしています。

まず20日新高値を付け、その後7日以内に新たに5日安値を更新するところまで下落する。5日安値を更新した場合、翌日の寄り付きで買い仕掛ける。

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

これで仕掛けのルールが決まりますので、この仕掛けに対し、ランダムな仕掛けより優位なのかを検証することができます。ストラテジーを書いて検証していきましょう。

ストラテジー構築

プログラムはこのようになります。

module Kabu
  class CbPbDays

    def initialize(n)
      @n = n
    end

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

      highs = soks[-27..-2].high(20)
      is_high = false
      highs.zip(soks[-8..-2]).each do |high,sok|
        next if high != sok.high
        is_high = true
        break
      end

      lows = soks[-6..-2].low(5)
      is_low = lows[-1] == soks[-2].low

      if not position.nil?
        if position.term >= @n
          return Action::Sell.new(code, date, soks[-1].open,1)
        else
          return Action::None.new(code, soks[-1].open)
        end
      end

      if is_high and is_low
        Action::Buy.new(code, date, soks[-1].open,1)
      else
        Action::None.new(code, soks[-1].open)
      end
    end
  end
end

仕切りルールを10日後の引けで仕切ることにして、理想的な取引がされているチャートを確認してみます。

image1

良さそうですね。これはうまくハマっているパターンですが、下記は天井を拾ったようなパターンです。

image2

N日検定

N日検定はその仕掛けがランダムな仕掛けより優位なのかを検証するためのものです。この検定では仕切りルールをN日後にした場合、適当なNであっても勝率が55%を超えるかを調べます。

ここではN=5,10,15,20,30,50について調べてみました。対象は33業種別株価指数の2007年〜2017年のデータです。

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

55%を切っていますので、果たしてと言ったところです。銘柄によるところが大きそうです。

仕切りパターン1

仕切りパターンの1つ目として紹介されているのがN日後に仕切るというものです。個人的には投げやりではないかと思いますが。

N日検定で一番勝率のよかった50日を用いて検証してみましょう。

Code net income trades win(%) pf average dd
I201 81.34 35 60.0 1.96 2.32 -22.34
I202 16.25 35 48.57 1.08 0.46 -48.34
I203 6.47 33 51.52 1.06 0.2 -52.42
I204 49.31 36 52.78 1.67 1.37 -19.11
I205 35.69 34 58.82 1.28 1.05 -32.89
I206 7.74 32 56.25 1.07 0.24 -22.19
I207 61.0 33 60.61 1.77 1.85 -20.45
I208 -32.36 35 42.86 0.73 -0.92 -24.21
I209 -28.42 35 54.29 0.84 -0.81 -50.97
I210 78.42 34 61.76 1.7 2.31 -32.21
I211 80.6 33 63.64 1.71 2.44 -31.55
I212 0.85 33 60.61 1.0 0.03 -63.78
I213 51.14 34 58.82 1.41 1.5 -47.91
I214 48.12 35 60.0 1.41 1.37 -39.09
I215 79.06 35 62.86 1.69 2.26 -27.39
I216 54.63 33 63.64 1.49 1.66 -22.28
I217 64.74 34 47.06 1.6 1.9 -58.04
I218 65.65 35 62.86 1.57 1.88 -39.01
I219 38.39 33 51.52 1.36 1.16 -20.28
I220 -21.96 31 41.94 0.85 -0.71 -41.3
I221 8.78 33 33.33 1.08 0.27 -29.49
I222 77.17 33 54.55 1.45 2.34 -31.19
I223 -82.87 35 37.14 0.62 -2.37 -61.69
I224 -57.32 35 40.0 0.64 -1.64 -76.7
I225 28.34 35 54.29 1.27 0.81 -44.11
I226 43.91 35 60.0 1.34 1.25 -27.58
I227 27.71 35 48.57 1.22 0.79 -48.25
I228 20.35 31 51.61 1.17 0.66 -29.75
I229 31.49 33 39.39 1.14 0.95 -47.21
I230 -20.37 33 48.48 0.87 -0.62 -53.69
I231 16.26 34 58.82 1.09 0.48 -51.08
I232 -20.3 33 51.52 0.89 -0.62 -53.69
I233 39.38 35 54.29 1.52 1.13 -31.2
平均 25.7 33.0 53.1 1.3 0.8 -39.4
偏差 40.98 1.41 8.17 0.34 1.2 14.57

無事プラスにはなりました。PFは1.3、平均収益は0.8%となっています。取引コストは勘定していませんので、この数字ではしんどいですね。

仕切りパターン2

2つめのパターンとして紹介されているのが、新高値で仕切るというものです。同じ20日新高値を用いましょう。コードこのとおりです。

module Kabu
  class CbPbHigh

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

      highs = soks[-27..-2].high(20)
      is_high = false
      highs.zip(soks[-8..-2]).each do |high,sok|
        next if high != sok.high
        is_high = true
        break
      end

      lows = soks[-6..-2].low(5)
      is_low = lows[-1] == soks[-2].low

      if not position.nil?
        if highs[-1] <= soks[-1].high
          return Action::Sell.new(code, date, highs[-1],1)
        else
          return Action::None.new(code, soks[-1].open)
        end
      end

      if is_high and is_low
        Action::Buy.new(code, date, soks[-1].open,1)
      else
        Action::None.new(code, soks[-1].open)
      end
    end
  end
end

チャートも確認しておきます。

image3

問題なさそうですね。動かしてみます。

Code net income trades win(%) pf average dd
I201 9.55 89 71.91 1.07 0.11 -27.4
I202 32.34 85 72.94 1.13 0.38 -59.03
I203 -5.73 85 69.41 0.96 -0.07 -35.32
I204 40.4 91 79.12 1.4 0.44 -35.8
I205 -35.7 79 69.62 0.79 -0.45 -42.28
I206 -41.41 79 63.29 0.79 -0.52 -38.04
I207 -18.27 87 78.16 0.88 -0.21 -46.71
I208 -15.44 80 73.75 0.88 -0.19 -32.11
I209 -21.86 85 75.29 0.9 -0.26 -43.5
I210 47.93 87 73.56 1.27 0.55 -41.06
I211 -41.52 86 70.93 0.81 -0.48 -55.82
I212 -139.87 66 60.61 0.5 -2.12 -64.16
I213 -27.74 92 73.91 0.88 -0.3 -50.29
I214 -43.48 81 71.6 0.75 -0.54 -39.5
I215 -49.47 88 77.27 0.77 -0.56 -57.28
I216 -50.11 85 70.59 0.75 -0.59 -58.45
I217 -60.49 77 64.94 0.71 -0.79 -41.29
I218 -20.1 93 75.27 0.89 -0.22 -52.24
I219 -54.09 77 75.32 0.74 -0.7 -53.82
I220 -73.54 74 70.27 0.67 -0.99 -43.73
I221 -24.57 78 65.38 0.79 -0.31 -18.02
I222 -88.99 70 70.0 0.72 -1.27 -60.76
I223 -66.44 72 63.89 0.68 -0.92 -58.85
I224 -25.07 84 70.24 0.84 -0.3 -34.68
I225 70.9 96 79.17 1.7 0.74 -16.74
I226 -44.52 86 75.58 0.76 -0.52 -56.33
I227 -26.72 85 74.12 0.83 -0.31 -20.15
I228 -117.74 66 59.09 0.52 -1.78 -61.27
I229 -178.04 66 57.58 0.49 -2.7 -82.51
I230 -68.99 79 68.35 0.74 -0.87 -57.14
I231 2.9 82 69.51 1.01 0.04 -69.77
I232 -56.22 78 66.67 0.78 -0.72 -62.69
I233 -13.03 82 69.51 0.89 -0.16 -21.35
  -36.5 81.0 70.5 0.9 -0.5 -46.6
  49.66 7.55 5.43 0.24 0.7 15.56

勝率が平均80%を超えるなかなかのシステムですが、収益がマイナスです。コツコツドッカン系といったところですね。ロスカットのルールを検討することで改善出来るのかもしれません。MFEを調べてみましょう。

勝ちトレードが経験した最大の含み損のヒストグラムを累積したものです。

image4

-3.2%当たりをロスカットラインに設定した場合8割程度の勝ちトレードは救えそうです。

ストラテジーはこんな感じです。

class CbPbHighStopLoss

    attr_accessor :loss_line

    def initialize
      @loss_cutted = false
    end

    def setup
      @last_position = nil
    end

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

      highs = soks[-27..-2].high(20)
      is_high = false
      highs.zip(soks[-8..-2]).each do |high,sok|
        next if high != sok.high
        is_high = true
        break
      end

      lows = soks[-6..-2].low(5)
      is_low = lows[-1] == soks[-2].low

      if position.nil?
        if is_high and is_low
          return Action::Buy.new(code, date, soks[-1].open,1)
        else
          return Action::None.new(code, soks[-1].open)
        end
      end

      is_loss_cut = position.gain(soks[-2].close,1) < @loss_line

      if is_loss_cut
        @last_position = position
        return Action::Sell.new(code,date,soks[-1].open,1)
      end

      if highs[-1] <= soks[-1].high
        return Action::Sell.new(code, date, highs[-1],1)
      else
        return Action::None.new(code, soks[-1].open)
      end
    end
  end

仮に-3.4%をロスカットラインだとして、チャートを確認します。

image5

image6

ロスカット、通常仕切り共に問題なさそうです。

ロスカットを-10%〜-1%に置きながら、損益などを確認します。

image7

image8

image8

-1%のロスカットを設定すると、収益は改善し、偏差も下がっています。ただ思うほどの効果はありませんでした。ちなみに-11%のロスカットラインはロスカットがない場合の値になっています。-10%と滑らかに接続しないのは気になります。MFEの累積グラフには-16%あたりまで勝ちトレードが経験した含み損があるので、このまま-16%くらいまでロスカットラインを切り下げていくと徐々に収益が改善するのかもしれません。

まとめ

CB-PBシステムについて2パターンの仕切り方法で検証を行ってみました。どちらもいまいちでした。シャンデ氏の著書には、十分に成熟したマーケットを対象にするとあるため、長い期間に渡ってヨコヨコであったり、緩やかに上昇しているような銘柄に絞れば話は変わってくるのかもしれません。

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

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

今回は破産確率という点でシステムを評価しましょう。破産確率はバルサラの破産確率が有名ですが、ここではシミュレーションを行って、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回のトレードのうちに破産する可能性があることを示しました。

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

疑似データは過去の日足をランダムピックしながら作るものです。まず作成方法について説明します。次に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年前に出会いたかったです。

このサイトは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を適用しないほうが僅かに収益は出るという結果に終わりました。

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

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

このサイトは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を用いたシステムを検証しましたが、あまり良い結果は得られませんでした。

使えそうにありません。

前回は「トレードシステムはどう作ればよいか①」より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でバックテストツールを作成し様々なストラテジーを検証することを目的としています。前回は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は簡単なシステムながらポテンシャルを秘めていることがわかりました。