トレードの評価指標のKPI設定（平均利益と平均損失の大きさが異なる場合）

　※この記事の文章は、元々自分用に書いていたメモになります。変な箇所などあればご指摘ください。



## はじめに

　以前、<a href="https://qiita.com/Sunset_Yuhi/items/25b7d0580c73d5e5a73a">「平均利益と平均損失の大きさが同じ場合」に、勝率やプロフィットファクターはどの程度あれば良さそうかを考察した</a>のですが、その後でつくだに博士さんという方から、「平均利益と平均損失の大きさが異なる場合」の情報を教えていただきました。
 
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">aをペイオフレシオと置き直して、計算が合いました！　a=1の場合は少し記事も書いてたのですが、aを使った場合も記事化するかもしれません。ありがとうございました！<br><br>トレードの評価指標のKPI設定（平均利益と平均損失の大きさが同じ場合） <a href="https://t.co/VSXWlCnuNm">https://t.co/VSXWlCnuNm</a> <a href="https://twitter.com/hashtag/Qiita%E3%82%A2%E3%83%89%E3%82%AB%E3%83%AC?src=hash&amp;ref_src=twsrc%5Etfw">#Qiitaアドカレ</a> <a href="https://t.co/G2GbCkEkjz">pic.twitter.com/G2GbCkEkjz</a></p>&mdash; サンセット (@Sunset_Yuhi) <a href="https://twitter.com/Sunset_Yuhi/status/1755283496883622169?ref_src=twsrc%5Etfw">February 7, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

　関係式はまだ比較的、すっきりした形にまとまったのではと思います。これで要するに、「勝率$p$で（平均）利益$ar$を得て、敗率$(1-p)$で（平均）損失$-r$を被る戦略」があった時、「その戦略のシャープレシオ$S$は、勝率$p$と取引回数$N$とペイオフレシオ（リスクリワード比、平均損益比率）$a$の関数で表せる」ことが分かりました。
 
　ですので、「この関係式を使えば、自分が望むシャープレシオを実現したい時に、勝率や取引回数やペイオフレシオの目標値を逆算できるのでは」と思ったのですが、これに対しても「勝率50%の（優位性がない）戦略でも、それなりに良い結果が偶然出てしまう」問題が存在しています。
 
　という訳で、「トレードの評価指標はどのくらいの値が出ていれば良いか」を改めて把握したくなったので、期待利得やプロフィットファクターなどの関係式（上のツイートの内容）を再検討した上で、「勝率の目標値（KPI）の設定方法」なども再び考えてみました。



## 期待利得、分散、シャープレシオ

　ある戦略を使って売買すると、勝率$p$で利益$ar$を得て、敗率$(1-p)$で損失$-r$を被るとします。この時、利得の期待値$E$は次のように書けます。
```math
\begin{align}
  E &= arp -r(1-p) = r(ap +p -1)
\end{align}
```

　利得の分散$V$は、<a href="https://bellcurve.jp/statistics/course/6716.html">取り得る分散と確率を掛けたものを、全て足せば計算できます</a>。ここでは、共通項を括りだして式の簡略化もしています。
```math
\begin{align}
  V &= [ar -r(ap +p -1)]^2 p +[-r -r(ap +p -1)]^2 (1-p)  \nonumber
  \\
  &= r^2(a -ap -p +1)^2 p +r^2(1 +ap +p -1)^2 (1-p)  \nonumber
  \\
  &= r^2(1 +a -p -ap)^2 p +r^2(p +ap)^2 (1-p)  \nonumber
  \\
  &= r^2 (1 +a)^2 (1 -p)^2 p +r^2 p^2 (1 +a)^2 (1 -p)  \nonumber
  \\
  &= r^2 (1 +a)^2 p(1 -p) [(1-p) +p]  \nonumber
  \\
  &= (1 +a)^2 r^2 p(1 -p)
\end{align}
```

　$N$[回]売買した場合、期待値は$E_{N}=r(ap +p -1)N$、$V_{N}=(1 +a)^2 r^2 p (1 -p)N$となり、この時にシャープレシオ$S$は次のように計算できます。
```math
\begin{align}
  S &= \frac{r(ap +p -1)N}{\sqrt{(1 +a)^2 r^2 p (1 -p)N}} = \frac{r[(1 +a)p -1] N}{(1 +a) r \sqrt{p (1 -p)N}} = \frac{(1 +a)p -1}{(1 +a) \sqrt{p (1 -p)}} \sqrt{N}
\end{align}
```



## シャープレシオから逆算した勝率の目標値

　シャープレシオ$S$の計算式を、勝率$p$について解くことを考えます。まず、両辺を2乗して分母を払うと、
```math
\begin{align}
  S &= \frac{(1 +a)p -1}{(1 +a) \sqrt{p (1 -p)}} \sqrt{N}  \nonumber
  \\
  S^2 &= \frac{(1 +a)^2 p^2 -2(1 +a)p +1}{(1 +a)^2 p(1-p)} N  \nonumber
  \\
  (1 +a)^2 S^2 p -(1 +a)^2 S^2 p^2 &= (1 +a)^2 N p^2 -2(1 +a)Np +N  \nonumber
\end{align}
```

　pの多項式としてまとめると、
```math
\begin{align}
  [(1 +a)^2 N +(1 +a)^2 S^2] p^2 -[2(1 +a)N +(1 +a)^2 S^2]p +N &= 0  \nonumber
  \\
  (1 +a)(N +S^2) p^2 -[2N +(1 +a) S^2]p +\frac{N}{1 +a} &= 0  \nonumber
\end{align}
```

　2次方程式の解の公式より、
```math
\begin{align}
  p &= \frac{2N +(1 +a) S^2 +\sqrt{[2N +(1 +a) S^2]^2 -4\cancel{(1 +a)}(N +S^2)\frac{N}{\cancel{1 +a}}}}{2(1 +a)(N +S^2)}   \nonumber
  \\
  &= \frac{2N +(1 +a) S^2 +\sqrt{\cancel{4N^2} +4(1 +a)NS^2 +(1 +a)^2 S^4 -\cancel{4N^2} -4NS^2}}{2(1 +a)(N +S^2)}   \nonumber
  \\
  &= \frac{2N +(1 +a) S^2 +S\sqrt{\cancel{4N} +4aN +(1 +a)^2 S^2 -\cancel{4N}}}{2(1 +a)(N +S^2)}   \nonumber
  \\
  &= \frac{2N +(1 +a) S^2 +S\sqrt{4aN +(1 +a)^2 S^2}}{2(1 +a)(N +S^2)}
\end{align}
```

　具体的な数値を代入して$p$を求めてみましょう。日本株などを日次で売買する場合、1年間の最大売買回数は$N=240$[回]程度となります。また、シャープレシオが例えば$S=2.0$あれば、損する確率を約$2.275$%程度に抑えられると考えられます（リターンが2、リスクが1とした時、$2\sigma$より大きく下振れると損するが、$2\sigma$の片側に出る確率が約$2.275$%のため）。

　また、ペイオフレシオ$a$は、日経平均株価などを買って翌営業日に売るという売買方法では、後述のように$a=0.95$くらいになるかと思うので、今回はこれを基準にしてみます。いよいよ$p$を求めますが、$p$の計算式が長いので、Pythonで計算できるようにします。$N=50$[回]、$S=2.0$、$a=0.95$とすると、プログラムは例えば次のように書けます。
 
```python
def func_p(N, S, a):
    numer = 2*N +S**2*a +S**2 +S*(4*N*a +S**2*a**2 +2*S**2*a +S**2)**(1/2)
    denom = 2*(N*a +N +S**2*a +S**2)
    return numer/denom

p = func_p(N=50, S=2.0, a=0.95)
print(p)
```

　これを実行すると、偶然と言えないために必要な勝率は、$p \sim 64.79$[\%]と求められました。「平均利益と平均損失の大きさが同じ場合」の計算と比べると、より高い勝率を求められることが分かります。



## 取引回数の目標値

　$N$[回]売買した時の期待利得$E_{N}=r(ap +p -1)N$も、ある程度大きくなければ売買する意味がないように思います。例えばある戦略で、年率のシャープレシオが10あったとしても、年率のリターンが1%しかないような場合、運用するメリットがないかもしれません。そこで次式から、年間の取引回数$N$を求めることを考えます。
```math
\begin{align}
  N &= \frac{E_{N}}{r(ap +p -1)}
\end{align}
```

　年率10[\%]のリターンが欲しいとします。勝率64.8[\%]の予測モデルを使い、日経平均株価のデータから$a=0.95$、損失時のリターンの大きさ（絶対値）を$r=0.008$とした時（詳細は後述）、$N$は次のように計算されます。
```math
\begin{align}
  \frac{0.10}{0.008(0.95 \times 0.648 +0.648 -1)} \sim 47.42  \nonumber
\end{align}
```

　この場合、年間で約48[回]売買する必要がある、と解釈できると思います。



## ランダムなトレードの上振れを考慮した勝率の目標値

　勝率$p=1/2$で$N$[回]売買した時の期待利得と分散は、次のように計算できます。
```math
\begin{align}
  E_{N} &= r(ap +p -1)N = r\left(a\frac{1}{2} +\frac{1}{2} -1\right) N = \frac{1}{2} (a -1)rN  \nonumber
  \\
  V_{N} &= (1 +a)^2 r^2 p(1 -p) N = (1 +a)^2 r^2 \frac{1}{2}\left(1 -\frac{1}{2}\right) N = \frac{1}{4} (1 +a)^2 r^2 N  \nonumber
\end{align}
```

　標準偏差は$\sigma = \frac{1}{2}(1 +a)r\sqrt{N}$となりますが、ランダムなトレードでも試行回数を繰り返せば、期待利得はある程度まで上振れる可能性があります。よく$2 \sigma$や$3 \sigma$と言われるような、標準偏差の正の実数倍で表される閾値を$\sigma_{th}$として、期待利得が満たすべき式を考えてみます。偶然で説明できる期待利得の最大値$\frac{1}{2} (a -1)rN +\frac{1}{2}(1 +a)r\sqrt{N} \sigma_{th}$より、実際の期待利得$r(ap +p -1)N$の方が大きい必要があるので、次のように書けるかと思います。
```math
\begin{align}
  \frac{1}{2} (a -1)rN +\frac{1}{2}(1 +a)r\sqrt{N} \sigma_{th} &\leq r(ap +p -1)N  \nonumber
  \\
  \frac{1}{2} (a -1) +\frac{(1 +a) \sigma_{th}}{2 \sqrt{N}} &\leq (1 +a)p -1  \nonumber
  \\
  \frac{1}{2} (a -1) +\frac{(1 +a) \sigma_{th}}{2 \sqrt{N}} +1 &\leq (1 +a)p  \nonumber
  \\
  \frac{1 +a}{2} +\frac{(1 +a) \sigma_{th}}{2 \sqrt{N}} &\leq (1 +a)p  \nonumber
\end{align}
```
```math
\begin{align}
  \therefore p &\geq \frac{1}{2} +\frac{\sigma_{th}}{2\sqrt{N}} = \frac{\sqrt{N} +\sigma_{th}}{2\sqrt{N}} = \frac{N +\sigma_{th}\sqrt{N}}{2 N}
\end{align}
```

　ここで例えば、取引回数を$N=50$[回]、上振れの閾値を$\sigma_{th}=2$とすると、$p$が満たすべき条件は次のように計算できます。
```math
\begin{align}
  p &\geq \frac{1}{2} +\frac{2}{2 \sqrt{50}} \sim 0.641  \nonumber
\end{align}
```

　この場合は、勝率が64%以上でないと、偶然で説明できてしまうことになります。ただし、取引回数$N$が大きくなるほど、要求される勝率は小さくても済みます。この検討だと「平均利益と平均損失の大きさが同じ場合」の場合と同じ計算式になりました


## プロフィットファクター

　プロフィットファクター$PF$は、平均損失の大きさに対する平均利益の大きさを表します。
```math
\begin{align}
  PF &= \frac{arp}{r(1-p)} = \frac{ap}{1-p} \geq 0
\end{align}
```

　利益が出るためには最低でも$1<PF$である必要があります。しかし、ランダムなトレードでも試行回数を繰り返せば、$PF$はある程度まで上振れる可能性があります。ランダムなトレードの勝率のおおよその上限は$p = \frac{\sqrt{N} +\sigma_{th}}{2\sqrt{N}}$となり、同時に敗率の下限は$1-p = \frac{\sqrt{N} -\sigma_{th}}{2\sqrt{N}}$となるので、プロフィットファクターが満たすべき条件は、次のように書けます。
```math
\begin{align}
  PF &\geq \frac{ a \frac{\sqrt{N} +\sigma_{th}}{2\sqrt{N}} }{ \frac{\sqrt{N} -\sigma_{th}}{2\sqrt{N}} } = a \frac{\sqrt{N} +\sigma_{th}}{\sqrt{N} -\sigma_{th}}
\end{align}
```



## 実際の株価データからの分析

　実際の株価データを使って、1回当たりのリターンの大きさ$r$、ペイオフレシオ$a$などを計算してみます。今回は日経平均株価に対して、定額（1万円など）を終値で買い、次の日の終値で売る戦略を取った場合を考えることにします。日経平均株価の日次データを取得し、日次変化率（日次リターン）を求めた後、上昇した日の平均利得（$ar$）と下落した日の平均損失（$-r$）を求めれば、必要な情報が揃います。

```python
import datetime
from dateutil import relativedelta
import pandas_datareader as pdr

date_max = datetime.date(2020, 1, 1)
#date_max = datetime.date.today()
date_min = date_max -relativedelta.relativedelta(months=20*12)  #months月前
#date_min = datetime.date(2000, 1, 1)

#^NKX:日経平均、^TPX:TOPIX、^SPX:S&P500、^NDX:ナスダック100、
df_price = pdr.data.DataReader('^NKX', 'stooq', date_min, date_max)
df_close = df_price['Close'].sort_index(ascending=True)
df_rate_day = df_close.pct_change().dropna()  #日次変化率
print(df_rate_day)
print('rate mean =', round(df_rate_day.mean(), 6))
print('rate abs mean =', round(df_rate_day.abs().mean(), 6))
print()

up_mean = df_rate_day[0.0<df_rate_day].mean()
down_mean = df_rate_day[df_rate_day<0.0].mean()
print('up mean =', round(up_mean, 6))  #ar
print('down mean =', round(down_mean, 6))  #r
print('payoff ratio =', round(-up_mean/down_mean, 6))  #a
```



## おわりに

　以上のことを踏まえて、トレードの成績を上げる方法を考えてみます。と言っても、「シャープレシオ$S$は、勝率$p$と取引回数$N$とペイオフレシオ$a$の関数で表せる」という話からすると、考えるべきことは「$p$、$N$、$a$をどのくらい上げるべきか」という問題に帰着するように思います。
 
　まず、ペイオフレシオ$a$を上げるには、平均損失をなるべく小さく抑えて、平均利益をなるべく大きくする必要があります。そのためには1つの考え方として、損失時には素早く損切りを行い（平均損失を一定値に抑える）、利得時にはなるべく大きく伸ばすようにする、という方法があるかと思います。具体的には、逆指値による損切りなどを設定するのが手っ取り早いのではと思います。
 
　勝率$p$を上げるには、具体的には株価予測モデルの正解率などを上げることになるかと思います。ただ、ある取引回数$N$でのバックテストの結果、$p$が偶然で説明できる値になっていないか、注意する必要がありそうです。また、機械学習などで単に予測モデルを作るだけだと、損切りラインの閾値などを学習させるのが難しいように思います。パラメータ最適化とか、別の手法も組み合わせて売買システムを考える必要がある気がします。
 
　取引回数$N$を上げるには、週足や日足ではなく、時間足や分足などのデータを基に取引回数を増やす必要があるように思います。ただ、日足のデータで売買する場合でも、同時に複数の戦略を走らせることで、取引回数を増やす方法もあるかもしれません。機械学習などのテクニックとして、複数のモデルを組み合わせてアンサンブルで精度を上げる方法がありますが、変に1つのモデルに集約して取引回数を減らすくらいなら、個別に戦略を動かして取引回数を増やした方が、もしかすると成績が良くなるのかもしれません。
 
　また最後に、今回は触れなかった話題を2つ挙げておきます。1つ目は、<a href="https://ad-van.co.jp/technical/article/barusara_keisanshiki/">バルサラの破産確率</a>の話です。トレードの勝率$p$、ペイオフレシオ$a$、損失許容額（この記事の内容で言えば損失時のリターンの大きさ$r$）が決まると、それに応じて破産確率を求めることができます。破産確率は限りなく0に近い方が良い訳ですが、この記事の内容と破産確率の話を合わせて考えると、ある戦略に対する損失許容額（とどのつまりは、賭け金額やレバレッジ比率）も求められそうです。
 
　2つ目は、少し話が変わりますが、プロスペクト理論の話です。この記事ではずっと、純粋な損益について考えてきましたが、その損益に対して感じる満足度（効用）は少し違ったものになります。人間の心には、利益が大きくなるほど限界効用が小さくなる、などの性質があると考えられています。それにより、利益が出た時には確実に確定させたい心理が働き、損失が出た時にはリスクを取って賭けに出る心理が働くと言われています。「ペイオフレシオ$a$を上げるには、平均損失をなるべく小さく抑えて、平均利益をなるべく大きくする必要がある」と書きましたが、これはすごく当たり前のことを言っているようで、実際の運用でこのルールを守ろうとすることは、心理的には実はかなり難しい可能性があります。この記事に書かれたことを、忠実に改善しようとするためには、そういった心理的な部分も知っておいた方がいいのではないかな、と個人的に思っています。

　バルサラの破産確率や、勝率の上げ方などについては、また書けることがありそうなので、考察がまとまったら書いてみたいと思います。