破産確率の計算

破産確率を自分でも計算してみようと思いまして調べてみました。

破産の確率

引用になりますが、こちらのサイトに破産の確率の説明が書いてありました。

<問題>

勝つと a 円もらえ、負けると b 円失う賭がある。勝つ確率を P とする。 あなたは、現在、n 円持っている。 この賭を際限なく繰り返すとき、破産する(所持金が0以下になる)確率はいくらか。

【注】 最後に借金が残る場合もありえます。たとえば、a = 15、b = 10、n = 10 のとき、「勝ち(25円) → 負け(15円) → 負け(5円) → 負け(-5円)」となれば、5円の借金をかかえて破産です。


P ≦ b / (a + b) のときは、「1回あたりの期待値 ≦ 0」なので、やるだけ無駄です。 この場合、破産の確率は「1」。つまり、際限なくやっていれば必ず破産します。

そこで、以下では P > b / (a + b) とします。


a = b で、n / b が整数の場合、破産の確率が次のようになることは、簡単に導けます(高校数学レベル)。

$$ \left(\frac{1-P}{P}\right)^{\frac{n}{b}} $$

n / b が整数でない場合は、上の公式で n / b の端数を切り上げて計算すればいいです。 例をあげておきます。

Aさんは、資金 200万円で株をやっている。 トレード1回ごとの勝率は 60%で、勝つときは 10万円儲け、負けるときは 10万円損をする。Aさんの破産の確率はいくらか。

これは、a = b = 10、n = 200、P = 0.6 とした状況と同じです。 よって、破産の確率は、次のようになります。

$$ \left(\frac{1-0.6}{0.6}\right)^{20}=0.0003\ldots $$

およそ 0.03%ですから、破産はなさそうですね。

もっとも、これには修正が必要かも知れません。 たとえば、負けが続いて残金が 10万円になっても、まだ破産していない以上、株を続けると想定しています。しかし、10万円で買える株などなかなかないでしょう。

そこで、残金が 55万円以下になったら破産(ゲームオーバーと言う方が適切だけど)と考えることにします。 145万負けたら破産ということなので、a = b = 10、n = 145、P = 0.6 と同じことです。 この場合の破産の確率は、次のように計算できます。 n / b = 14.5 ですが、端数を切り上げ、15として計算します。

$$ \left(\frac{1-0.6}{0.6}\right)^{15}=0.00228\ldots $$

およそ 0.23%ですか …。 まあ、大丈夫でしょ。


というわけで、a = b の場合は簡単です。 そうでないときは、どうするのか?

a と b が異なる整数の場合、数式は書き出せるのですが、高次方程式の解(それも複素数の解)を求める必要があり、実用的でありません。 簡単な近似式がないものかと少し考えてみたのですが、わかりませんでした。

そこで近所の図書館へ行き、『確率論とその応用』 という本(W・フェラー著、確率論の名著らしいです)を借りてパラパラ見てみると …。 ありました!! さすがに名著といわれるだけのことはあります(笑)

フェラーの本に出ている式に少し手を加えることで、次のように結論できます。

まず損益比 R を R = a / b で定義します。 0 < x < 1 の範囲における、次の方程式の解を S とします(この範囲における解は1つしかありません)。

$$ Px^{R+1}-x+1-P=0 $$

このとき、次の評価式が成立します。

$$ S^{\frac{n}{b}+1}<破産の確率\leqq S^{\frac{n}{b}} $$

n / b と R がともに整数の場合は、右辺の等号が成立します。つまり、$破産の確率=S^{\frac{n}{b}}$ です。

この評価式、みなさんは知ってましたか? もっと良い評価式もあるのでしょうか。私は、知らないのですが。

なお、この評価式の証明は、数学の素養があればそれほど難しくありません。 知りたい人は、フェラーの本を見てください。フェラーの 『確率論とその応用』 は、「1」 と 「2」 があり、それぞれ上巻・下巻に分かれています(つまり全4巻)。 この評価式は、「1」 の下巻、461ページにある式(8・12)から導くことができます。


例をあげましょう。

Bさんは、150万円で株をやっている。トレード1回ごとの勝率は 40%だが、勝つときは 20万円儲け、負けるときは 8万円損をする。 Bさんの破産の確率はいくらか。

ここでも資金に下限を設け、残金が 50万円以下になったら破産(ゲームオーバー)と考えましょう。 つまり、100万円の損すると破産ですから、n = 100 と見なせばいいです。 R = 20 / 8 = 2.5、P = 0.4 ですから、方程式は次のようになります。

$$ 0.4x^{3.5}-x+0.6=0 $$

この方程式の 0 < x < 1 の範囲における解をパソコンで求めると x = 0.738… です。 n / b = 100 / 8 = 12.5 ですから、次の式が成立。

$$ (0.738\ldots)^{13.5}<破産の確率\leqq (0.738\ldots)^{12.5} $$

関数電卓で計算すると、

$$ 0.016\ldots<破産の確率\leqq 0.022\ldots $$

破産の確率は 1.6~2.2%くらいですね。ちょっと危険みたいです。


さて、賭け金を一定にするのではなく、資金に対して一定の比率で賭けていく場合はどうでしょうか。 つまり、その時点の資金を A 円とするとき、一定の比率 k (0 < k < 1)を用いて、勝てば R × k × A 円儲け、負ければ k × A 円損するように賭けるとします。

たとえば、損益比 R(= 利益 ÷ 損失)が 2 とします。k = 0.1 なら、常に資金の 10%をリスクにさらします。 資金 100万円なら、負けは 10万円の損、勝ちは 20万円の得となるように賭け、それに勝って資金が 120万円になれば、次は、負けは 12万円の損、勝ちは 24万円の得となるように賭けるわけです。

はじめの資金を A0 円とし、資金が B 円以下になったら破産とします。

【注】 定率の場合、破産基準の B 円の設定は不可欠です。 なにも条件を課さないと、たとえば k = 0.5 の場合、残金が1円でも 0.5円を賭け、それに負けると次は 0.25円を賭け、さらに負けても 0.125円を賭け … と次々に小さな金額を賭けてくるので、いつまでたっても破産しません。

W 回勝って、L 回負けたとき、資金が B 円以下になって破産する条件は、次の式です。

$$ (1+Rk)^{W}(1-k)^{L}A_{0}\leqq B $$

対数をとって変形すると次のようになります。

$$ W\log(1+Rk)-L\bracevert\log(1-k)\bracevert+\log\left(\frac{A_{0}}{B}\right)\leqq 0 $$

a、b、n を次のように定義します。

$$ a=\log(1+Rk) $$

$$ b=\bracevert\log(1-k)\bracevert $$

$$ n=\log\left(\frac{A_{0}}{B}\right) $$

そうすると、上の式は、

$$ Wa-Lb+n\leqq 0 $$

と同じことです。 結局、この問題は 「資金が n 円、勝つと a 円儲け、負けると b 円失うときの破産の確率は?」 と同じです。 つまり、このページのはじめの <問題> に還元されるわけです。

上に書いた確率の評価式は、a、b、n が整数でなくても成立するので、それを適用すれば評価が出せます。


方程式 $Px^{R+1}-x+1-P=0$ を解く必要があるので、計算ソフトを作ってみました。 ちゃちなソフトですが、よかったらご自由にお使いください。ダウンロードはこちらのページからどうぞ。

パソコンを使うなら、もっと正確な値を出す方法があるのかもしれませんけどね。

破産の確率

破産確率計算

上記の説明を参考に計算できるようにしてみました。

賭け金を資金に対して一定の比率で賭けた場合の、破産確率の上限の方の計算をしています。

ソース

ソースはこちらです。

方程式 $Px^{R+1}-x+1-P=0$ のところでImmutable.jsを使ってみましたが、遅いです・・ Macなら1秒以内だけど、iPhoneだったら計算までにどれくらいかかるのか・・ 小数点以下の有効桁数を5桁として、絶対値の最小を求めるのにソートしているところが遅いみたいだけど、もっと効率的にできるのかな。

取引数量計算と同じようにReactも使いました。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>破産確率計算</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.38/browser.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>
  </head>
  <body>
    <div id="calculation"></div>
    <script type="text/babel">
      const style = {
        number: {
          color: "#555",
          fontFamily: 'Avenir, "Open Sans", "Helvetica Neue", Helvetica',
          fontSize: "14px",
          textAlign: "right"
        }
      };
      class Calculation extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            value: '0.00'
          };
        }
        render() {
          return (
            <div>
              <form>
                <table>
                  <tbody>
                    <tr>
                      <th width="30%">
                        資金(A)
                      </th>
                      <td width="70%">
                        <input type="text"
                          ref={ c => this._A = c }
                          onFocus={ this.handleFocus.bind(this) }
                          onBlur={ this.handleBlur.bind(this) }
                          pattern="\d*"
                          placeholder="1,000,000"
                          style={ style.number } />
                      </td>
                    </tr>
                    <tr>
                      <th>
                        破産基準(B)
                      </th>
                      <td>
                        <input type="text"
                          ref={ c => this._B = c }
                          onFocus={ this.handleFocus.bind(this) }
                          onBlur={ this.handleBlur.bind(this) }
                          pattern="\d*"
                          placeholder="100,000"
                          style={ style.number } />
                      </td>
                    </tr>
                    <tr>
                      <th>
                        賭け金の比率(k)
                      </th>
                      <td>
                        <input type="text"
                          ref={ c => this._k = c }
                          onFocus={ this.handleFocus.bind(this) }
                          onBlur={ this.handleBlur.bind(this) }
                          pattern="\d*"
                          placeholder="0.02"
                          style={ style.number } />
                      </td>
                    </tr>
                    <tr>
                      <th>
                        勝率(P)
                      </th>
                      <td>
                        <input type="text"
                          ref={ c => this._P = c }
                          onFocus={ this.handleFocus.bind(this) }
                          onBlur={ this.handleBlur.bind(this) }
                          pattern="\d*"
                          placeholder="0.4"
                          style={ style.number } />
                      </td>
                    </tr>
                    <tr>
                      <th>
                        平均利益(a)
                      </th>
                      <td>
                        <input type="text"
                          ref={ c => this._a = c }
                          onFocus={ this.handleFocus.bind(this) }
                          onBlur={ this.handleBlur.bind(this) }
                          pattern="\d*"
                          placeholder="30"
                          style={ style.number } />
                      </td>
                    </tr>
                    <tr>
                      <th>
                        平均損失(b)
                      </th>
                      <td>
                        <input type="text"
                          ref={ c => this._b = c }
                          onFocus={ this.handleFocus.bind(this) }
                          onBlur={ this.handleBlur.bind(this) }
                          pattern="\d*"
                          placeholder="10"
                          style={ style.number } />
                      </td>
                    </tr>
                    <tr>
                      <th>
                        破産確率
                      </th>
                      <td>
                        <span>{ this.state.value }%</span>
                      </td>
                    </tr>
                    <tr>
                      <th></th>
                      <td>
                        <input type="button" value="計算する" onClick={ this.handleClick.bind(this) } />
                      </td>
                    </tr>
                  </tbody>
                </table>
              </form>
            </div>
          );
        }
        addComma(v) {
          return v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,');
        }
        removeComma(v) {
          return v.replace(/,/g, '');
        }
        calculateX(P, R) {
          const SCALE = 5;
          const xs = Immutable.Range(0, 1, 1 / Math.pow(10, SCALE));
          const Ss = xs.map(x => P * Math.pow(x, R + 1) - x + 1 - P);
          const min = Ss.sortBy(S => Math.abs(S)).minBy(S => Math.abs(S));
          const result = Ss.keyOf(min) / Math.pow(10, SCALE);
          return result;
        }
        calculateB(P, k, R, A, B) {
          const a = Math.log(1 + R * k);
          const b = Math.abs(Math.log(1 - k));
          const n = Math.log(A / B);
          const x = this.calculateX(P, a / b);
          const result = Math.pow(x, n / b);
          return result;
        }
        calculate() {
          const A = this.removeComma(this._A.value);
          const B = this.removeComma(this._B.value);
          const k = this.removeComma(this._k.value);
          const P = this.removeComma(this._P.value);
          const a = this.removeComma(this._a.value);
          const b = this.removeComma(this._b.value);
          if (!A || isNaN(A)) return;
          if (!B || isNaN(B)) return;
          if (!k || isNaN(k)) return;
          if (!P || isNaN(P)) return;
          if (!a || isNaN(a)) return;
          if (!b || isNaN(b) || b === 0) return;
          const R = a / b;
          this.setState({ value: (this.calculateB(P, k , R, A, B) * 100).toFixed(2) });
        }
        handleClick(event) {
          this.calculate();
        }
        handleFocus(event) {
          event.target.value = this.removeComma(event.target.value);
        }
        handleBlur(event) {
          event.target.value = this.addComma(event.target.value);
        }
      };
      ReactDOM.render(
        <Calculation />,
        document.getElementById('calculation')
      );
    </script>
  </body>
</html>

同じような計算をみんなの外為のsmartFXでもやっていますね。 こちらは方程式 $Px^{R+1}-x+1-P=0$ のところで半分に分けながら、0に近づけながら計算しているため効率的な気がします。

参考

12 October 2016 追記

システムトレード 基本と原則』の中に破産確率の計算について書いてありました。

この本の「第4章原則–自己啓発 破産リスクを避ける」のところでは $\left(\frac{1-P}{P}\right)^{\frac{n}{b}}$ の計算式と同じことが説明されているようです。

リスクリワードレシオが1を上回る場合(平均利益と平均損失が同じではない場合で、1を下回るならやるだけ無駄です。)の計算式については次のように書いてありますね。

残念なことだが、平均利益が平均損失を上回る場合に破産確率を計算できる単純な公式はない。

その代わりに付録A、付録B、付録Cとして破産確率のシミュレーターについて記載されていますね。

付録Bに示したナウザー・バルサラの「マネー・マネジメント・ストラテジーズ・フォー・フューチャーズ・トレーダーズ(Money Management Strategies for Futures Traders)」のロジックを私たちなりに解釈し、それに基づいて次のモデルを書いた。

このモデルは次の変数を使っています。

  • 定率の場合
    • 勝率
    • ぺイオフレシオ(平均利益 ÷ 平均損失)
    • 資金額
    • 1トレード当たりに口座の何パーセントのリスクをとりたいか
    • 口座が何パーセントのドローダウンを被ったときに破産と解釈するか
  • 固定リスク額の場合
    • 勝率
    • ぺイオフレシオ(平均利益 ÷ 平均損失)
    • 資金額
    • 口座資金を何ユニットに分けたいのか
    • 口座が何パーセントのドローダウンを被ったときに破産と解釈するか

ロジックは次のようになっています。

  • 乱数を生成する関数を使って、勝ちトレードか負けトレードかを決める
  • 1トレードが終わると、ドローダウンの大きさを測って、連続した純資産曲線を作る
  • 純資産が最後に一番高かったところから、破産水準と定義したドローダウンに達すると、次の公式を用いて破産確率を計算する
  • 破産確率 = (純資産の直近の最大値から負けトレードの数) ÷ (純資産の直近の最大値からのトレードの総数)

“シミュレーター"という言葉にあるように、1トレード、1トレードを仮想的に行っていく感じになるようですね。 ドローダウンが破産と解釈するところまできたら、純資産の最大値からのトレード総数と、純資産の最大値からの負けトレード数から確率を計算していると。 純資産曲線が2億ドルに達するか、トレード数が1万回に達すると、破産を免れたとみなしているようです。

このシミュレーションをする代わりに、$S^{\frac{n}{b}+1}<破産の確率\leqq S^{\frac{n}{b}}$ の評価式で求められるということになるのかな。

数学的な素養がないから証明ができないんですけど・・

期待値の計算もしてみました。

破産確率は実際のところ完全に0にはならないけど、限りなく0に近い0%にすることが望ましいです。