週単位、月単位で勝つためのトレード数 (2017/10/05)

週単位、月単位で勝つには勝率がどのくらいのトレードを1日に何回行う必要があるかということを考えてみる。

ここでは「週単位、月単位で勝つ」を週単位、月単位で損益がプラスとなる確率が80%以上と見なすこととする。また、1トレード当たりの利益/損失は常に一定で「1.0」としておく。

それでは、1トレード当たりの勝率を55%とした場合、トレードを1日に何回行う必要があるかをシミュレーションしてみる。

○以下のプログラムを実行する。

threshold = 0.8
wp = 0.55

def func(n, r):
    if n == 0 or r == 0:
        return 1
    else:
        return func(n, r - 1) * (n - r + 1) / r

prob = 0.0
n_trade = -1
while (prob < threshold):
    n_trade = n_trade + 2 # 必ず奇数にする
    prob = 0.0
    for i in range(int((n_trade + 1) / 2), n_trade + 1):
        r = i
        temp = func(n_trade, r) * wp**r * (1 - wp)**(n_trade - r)
        prob = prob + temp
print("週単位で勝つための1日当たりのトレード数 = ", n_trade / 5.0)
print("月単位で勝つための1日当たりのトレード数 = ", n_trade / 20.0)

週単位で勝つための1日当たりのトレード数 =  14.2
月単位で勝つための1日当たりのトレード数 =  3.55

シミュレーションによると、週単位で勝つなら14.2回、月単位で勝つなら3.55回は必要ということになる。なかなか大変だ。

勝率55%という設定は低いように思われるかもしれない。だが、利益/損失=1.0という条件下では勝率55%でもまずまずである。

勝率とペイオフレシオ (2017/07/08)

勝率とペイオフレシオの関係がどのようであるかを調べてみる。

勝率の高い戦略が優れているとは限らない。ペイオフレシオが低ければ勝率が高くても負ける戦略となる場合がある。

逆に、ペイオフレシオの高い戦略が優れているとは限らない。勝率が低ければペイオフレシオが高くても負ける戦略となる場合がある。

要するにバランスが重要だ。それを考慮せずに「損小利大」はよいとか、「損大利小」はだめとか言っても無意味である。

さて、私は勝率が高ければペイオフレシオは低く、勝率が低ければペイオフレシオは高い、つまり、トレードオフの関係にあると考えている。勝率もペイオフレシオも高いというのが理想ではある。だが、そう簡単に実現できることではない。

もし、勝率とペイオフレシオがトレードオフの関係にあるとすれば、

平均利益 / 平均損失 = 負け数 / 勝ち数

という関係を想定することができるだろう。これを整理すると、

ペイオフレシオ = 負け数 / 勝ち数
ペイオフレシオ = (負け数 / (勝ち数+負け数)) / (勝ち数 / (勝ち数+負け数))
ペイオフレシオ = (1 - 勝率) / 勝率
ペイオフレシオ * 勝率 = 1 - 勝率
ペイオフレシオ * 勝率 + 勝率 = 1
(ペイオフレシオ + 1) * 勝率 = 1
勝率 = 1 / (ペイオフレシオ + 1)

となる。

すると、

勝率 = 傾き * (1 / (ペイオフレシオ + 1)) + 切片

というモデルを想定することができる。特に理由がなければ、傾きは1、切片は0になると考えられる。

では上のモデルをランダムウォークのデータを使って検証してみる。

①この記事で使うライブラリをインポートする。

import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit

②ペイオフレシオごとの勝率を求める。

n = 1000
max_iter = 10000
wp_long = np.empty(9)
wp_short = np.empty(9)
payoff_ratio_long = np.empty(9)
payoff_ratio_short = np.empty(9)

for i in range(9):
    profit = i + 1
    loss = 9 - i
    win_long = 0
    lose_long = 0
    win_short = 0
    lose_short = 0
    for j in range(max_iter):
        rnd = np.random.randn(n) * 0.01
        close = np.cumsum(rnd) + np.log(100)
        close = np.exp(close)
        count = 0
        for k in range(n):
            if count < k:
                count = k
            if close[k] >= 100 + profit:
                win_long += 1
                lose_short += 1
                break
            if close[k] <= 100 - loss:
                lose_long += 1
                win_short += 1
                break
    wp_long[i] = win_long / (win_long + lose_long)
    wp_short[i] = win_short / (win_short + lose_short)
    payoff_ratio_long[i] = profit / loss
    payoff_ratio_short[i] = loss / profit

先ず、ペイオフレシオを1:9、2:8、3:7、4:6、5:5、6:4、7:3、8:2、9:1で場合分けする。次にランダムウォークのデータを作り、それぞれのペイオフレシオでの勝敗をカウントするシミュレーションを1万回行って勝率を求める。

検証は買いの場合と売りの場合の2つのパターンで行った。同じ値幅での上昇確率は下落確率よりわずかに高く、買いが売りよりわずかに有利だと考えられるからである。これについては以下を参照。

https://storage.googleapis.com/imoz-jp/slides/160321_trading.pdf(p19-22)

③グラフを表示する。

plt.plot(payoff_ratio_long, wp_long, label='wp_long')
plt.plot(payoff_ratio_short, wp_short, label='wp_short')
plt.xlabel('Payoff Ratio')
plt.ylabel('Winning Percentage')
plt.xlim(0, 9)
plt.ylim(0, 1)
plt.legend(loc="upper right")
plt.savefig('wp_por.png', format='png', dpi=150)
plt.show()

わずかに買いの勝率が売りの勝率より高いことが分かる。

④モデルを作成する。

def model(payoff_ratio, a, b):
    return a * (1 / (1 + payoff_ratio)) + b

⑤モデルの傾きと切片を求める。

popt, pcov = curve_fit(model, payoff_ratio_long, wp_long)
slope_long = popt[0]
intercept_long = popt[1]
popt, pcov = curve_fit(model, payoff_ratio_short, wp_short)
slope_short = popt[0]
intercept_short = popt[1]

⑥モデルを表示する。

print('Long:')
print(
      '\t Winning Percentage = ', slope_long, ' * (1 / (Payoff Ratio + 1)) + ',
      intercept_long)
print('Short:')
print(
      '\t Winning Percentage = ', slope_short,
      ' * (1 / (Payoff Ratio + 1)) + ', intercept_short)

Long:
         Winning Percentage =  0.887583333429  * (1 / (Payoff Ratio + 1)) +  0.0613638886528
Short:
         Winning Percentage =  0.887583333879  * (1 / (Payoff Ratio + 1)) +  0.0510527775029

当初、期待していた「傾きが1、切片が0」となる結果とは少し違う。誤差とするにはやや大きすぎるように思う。だが、なぜこうなるかは分からない。

とりあえず目安としては買いと売りを分けずに

勝率 = 0.9 * (1 / (ペイオフレシオ + 1)) + 0.05

くらいに考えておけばいいだろうか。

これはランダムウォークで予測される勝率である。したがって、これより大きな勝率でなければランダムウォークに勝っていないことになる。

的中率とシャープレシオ (2017/07/06)

的中率とシャープレシオとの間にどのような関係があるかをシミュレーションによって調べてみる。

単純化のため、ここでいくつかの仮定を置く。

先ず、ボラティリティは1.0で固定とする。固定でさえあれば、実際にはどの数値でも結果は変わらない。

次に1年当たりのトレード数を260回とする。これは数値を変えると結果も変わるので動かせない。この数値は1年当たりの営業日が260日であることに基づく。イメージとしては毎日、上がるか下がるかを予測して売買し、1日の損益の絶対値は常に一定、と考えればいい。

最後にコストは考慮していない。

それではシミュレーションを始める。

①この記事で使うライブラリをインポートする。

import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit

②的中率とそれに対応したシャープレシオを計算する。

start = 50
end = 105
step = 5
n = int((end - start) / step)
accuracy = np.array(range(start, end, step)) / 100
sharpe_ratio = np.empty(n)
volatility = 1.0
trades = 260
for i in range(n):
    ret = ((volatility*accuracy[i]) - (volatility*(1.0-accuracy[i]))) * trades
    risk = volatility * np.sqrt(trades)
    sharpe_ratio[i] = ret / risk

的中率は50-100%の範囲で5%刻みとする。

③グラフを表示する。

plt.plot(accuracy, sharpe_ratio)
plt.xlabel('Accuracy')
plt.ylabel('Sharpe ratio')
plt.xlim(0.5, 1.0)
plt.savefig('sharpe_ratio_accuracy.png', dpi=150)
plt.show()

グラフを見ると、的中率とシャープレシオは比例していることが分かる。

④的中率とシャープレシオの関係を示すモデルを作成する。

def model(accuracy, slope, intercept):
    return slope * accuracy + intercept

上のグラフから以下のような関係を想定している。

シャープレシオ = 傾き * 的中率 + 切片

⑤モデルの傾き、切片を求める。

popt, pcov = curve_fit(model, accuracy, sharpe_ratio)
slope = popt[0]
intercept = popt[1]
print('Sharp Ratio = ', slope, ' * Accuracy + ', intercept)

Sharp Ratio =  32.2490309932  * Accuracy +  -16.1245154966

求められた傾き、切片によると、的中率が5%上昇するだけでシャープレシオは約1.61上昇するということが分かる。的中率で見ると、5%くらい大した違いではないように思うかもしれない。だが、これは大変な改善なのである。

もし的中率が70%であったら、

シャープレシオ = 32.2490309932 * 0.7 + (-16.1245154966) = 6.4498061986399975

となる。

シャープレシオが3.0以上なら、それは素晴らしい戦略だろう。6.0を超えるとなると、もはや尋常ではない。言い換えれば、的中率が70%に達するというのは尋常ではないのである。

機械学習、またはディープラーニングで株価予測的中率が○○%になった、というような話をよく聞く。だが、実際に尋常ではない素晴らしい成果が得られたのか、それとも何らかの間違いを犯していたり、単なる誇大広告であったりしないか、しっかりと吟味する必要がある。

週単位、月単位で勝つためのシャープレシオ (2017/05/14)

あるトレード戦略が週単位、月単位で勝つためにはどの程度のシャープレシオが必要かということを考えてみる。

勝てる戦略とは

例えば、年単位の利益が10%、年単位のリスクが10%だとする。すると、シャープレシオは

\[ sharpe = 0.1 / 0.1 = 1.0 \]

となる。したがって、1年後の想定利益は10±10%、つまり0~20%となる。

ところで、リスクは1σで計算している。したがって、想定利益は68.27%の確率でその範囲内に収まる。つまり1年後の利益がプラスである確率は68.27%以上となる。なぜ68.27%「以上」になるかというと、年単位20%を越える利益となる可能性もあるからである。

もう少し正確には

\[ prob = 68.27 + (100 - 68.27) / 2 = 84.135 \]

で、84.135%となる(手計算なので誤差あり)。もちろん、これは机上の空論だ。だが、一応の目安にはなる。

ここではプラスとなる確率が84.135%以上であれば「勝てる戦略」と見なすことにする。すると、シャープレシオが1.0以上なら年単位では「勝てる戦略」と言える。同様に週単位、月単位のシャープレシオが1.0以上であれば、週単位、月単位で「勝てる戦略」と言える。

シャープレシオの計算式

ここで、週単位、月単位、年単位のシャープレシオの計算式を定義しておく。

ここでは1週間を5営業日、1ヶ月を20営業日、1年を260営業日としておく。また、1日単位の利益をr、1日単位のリスクをsとする。また、リスクフリーレートは考慮しないことにする。

すると、

\[ sharpe_{weekly} = \frac {5r} {\sqrt{5s}} \] \[ sharpe_{manthly} = \frac {20r} {\sqrt{20s}} \] \[ sharpe_{yearly} = \frac {260r} {\sqrt{260s}} \]

となる。

週単位で勝つためのシャープレシオ

では、先ず、週単位のシャープレシオが1.0以上であるには、年単位のシャープレシオがどのくらい以上でなければならないかを考える。

\[ \frac {sharpe_{yearly}} {sharpe_{weekly}} = \frac {\frac {260r} {\sqrt{260s}}} {\frac {5r} {\sqrt{5s}}} \] \[ {sharpe_{weekly}} = 1, \ \frac {sharpe_{yearly}} {1} = \frac {\frac {260r} {\sqrt{260s}}} {\frac {5r} {\sqrt{5s}}} \] \[ sharpe_{yearly} = \frac {\frac {260r} {\sqrt{260s}}} {\frac {5r} {\sqrt{5s}}} \] \[ = \frac {260r} {\sqrt{260s}} \times \frac {\sqrt{5s}} {5r} \] \[ = \frac {52} {\sqrt{52}} \times \frac {1} {1} \] \[ = \frac {52} {\sqrt{52}} \] \[ = \frac {52 \times \sqrt{52}} {\sqrt{52} \times \sqrt{52}} \] \[ = \frac {52 \times \sqrt{52}} {52} \] \[ = \sqrt{52} \] \[ \approx 7.21 \]

となる。つまり、週単位のシャープレシオが1.0以上であるには、年単位のシャープレシオが約7.21以上である必要がある。

月単位で勝つためのシャープレシオ

次に、月単位のシャープレシオが1.0以上であるには、年単位のシャープレシオがどのくらい以上でなければならないかを考える。

\[ \frac {sharpe_{yearly}} {sharpe_{monthly}} = \frac {\frac {260r} {\sqrt{260s}}} {\frac {20r} {\sqrt{20s}}} \] \[ {sharpe_{monthly}} = 1, \ \frac {sharpe_{yearly}} {1} = \frac {\frac {260r} {\sqrt{260s}}} {\frac {20r} {\sqrt{20s}}} \] \[ sharpe_{yearly} = \frac {\frac {260r} {\sqrt{260s}}} {\frac {20r} {\sqrt{20s}}} \] \[ = \frac {260r} {\sqrt{260s}} \times \frac {\sqrt{20s}} {20r} \] \[ = \frac {13} {\sqrt{13}} \times \frac {1} {1} \] \[ = \frac {13} {\sqrt{13}} \] \[ = \frac {13 \times \sqrt{13}} {\sqrt{13} \times \sqrt{13}} \] \[ = \frac {13 \times \sqrt{13}} {13} \] \[ = \sqrt{13} \] \[ \approx 3.61 \]

となる。つまり、月単位のシャープレシオが1.0以上であるには、年単位のシャープレシオが約3.61以上である必要がある。

まとめ

年単位のシャープレシオが3.61以上というのはなかなか難しい。まして、7.21以上というのは更に難しい。したがって、少なくとも単体の戦略で週単位、月単位で勝つということはなかなか容易ではないと言える。

逆に言えば、週単位、月単位で勝つためには複数の戦略が必要ということになるだろう。しかし、複数の戦略を用いるにしても、お互いの戦略のパフォーマンスが正の相関であれば、あまり意味がない。しかし、無相関、負の相関の戦略同士を組み合わせるというのは「言うは易く行うは難し」なのである。

だとすれば、週単位、月単位で勝つというのは理想として求めるべきものではある。だが、実際には難しいこととして、週単位、月単位で負けることはよくあること、とゆったりした気持ちで取り組むべきだろう。

スリッページの損得

スリッページは順張り(逆張り)に不利(有利)

スリッページというと何となく良くないイメージがあるかと思う。注文を出して自分が想定した価格で売買できなかった場合、売買価格がトレーダーの不利になるように動くことが多いような気がするものだ。ブローカーが本当に公正であるかということに対する不信感も関係あるだろう。だが、それについてはここでは触れない。

私は経験上、スリッページは順張りには不利に、逆張りには有利に動く傾向があるように感じている。あくまでも個人的な印象であって、きちんと検証したわけではない。ただ、バックテストにおいても、実際のトレードにおいても、そのような局面に出くわすことが多い「気がする」のである。

逆張りでは1分1秒を争うようなことはない

例えば、逆張り戦略において、1分足で計算期間50のケースと5分足で計算期間10のケースとでバックテストしたとする。いずれも50分であるから、パフォーマンスにおいて大差はないと思うだろう。実際、大差はないが、5分足のほうがパフォーマンスがよいことが多い「気がする」(これより後は「気がする」は省略)。

私は順張りが苦手で、トレードはもっぱら逆張りである。普段は逆張りシステムにシグナルをメールで知らせるようにしている。メールを確認してからトレードするのであるから、当然、システムより遅れる。5分、10分遅れることはしょっちゅうである。もちろん、トレード機会を失うこともあるが、むしろシステムより有利なレートで売買できることが多い。

トレードというとモニターをいくつも並べてリアルタイムで情報を追い、瞬時の判断が勝敗を決めるというようなイメージを持っている人を見かける。だが、私はスマートフォン1つでトレードしている。チャートもシグナルが来てから確認するが、まったく問題はない。1分1秒を争うようなことはないのである。

ブレイクアウト戦略の劣化がひどい

順張りでは逆のことが起きる。といっても普通の順張りでは使えそうな戦略を作れた試しがないので、ここではブレイクアウト戦略について述べる。ブレイクアウトは5分足より1分足のほうがパフォーマンスのよいことが多い。MT4であれば、モデルを「全ティック」でバックテストしたほうがパフォーマンスはよい。となると、これは1分1秒を争うのである。

私は以前、とても素晴らしい(と思った)ブレイクアウト戦略を作ったことがある。バックテストでもウォークフォワードテストでも素晴らしいパフォーマンスである。私がそれまで、いや、今まで作ったどの戦略よりも優れていた。資産曲線はほぼ一直線の右肩上がりであった。

つい浮かれてしまい、デモ口座で試すこともあまりせずに実弾を投入した。これは手動では無理なのでEAを使った。大儲け間違い無しと思っていたのだが、案に相違してちっとも勝てない。おかしいと思い、取引履歴と同期間のバックテストを比較してみた。すると、バックテストでは勝っているのである。

実際の取引とバックテストとの間で生じた乖離の原因はスリッページである。エントリーにしろ、エグジットにしろ、わずかにバックテストより不利なレートで売買していたのである。

このブレイクアウト戦略はトレード機会は多いが、1トレード当たりの利益は小さかった。つまり薄利多売である。この戦略はスリッページに耐えられなかったのである。ブレイクアウト戦略は机上のパフォーマンスは素晴らしいが、実際のトレードでは劣化がひどい。一方、逆張り戦略では同じ期間でのバックテストと取引履歴とで結果はほぼ一致している。

でも、ただの言い訳かも

とはいうものの、実際には順張りが苦手な私のただの言い訳かもしれない。得意な戦略ではうまくいくが、苦手な戦略ではうまくいかない。これは当たり前のことだ。ただ、スリッページは有利に動くこともあれば、不利に動くこともあり、薄利多売の戦略には致命的な影響を与えるということは最後に強調しておきたい。

(2017/02/15更新)