ランダムウォークの勝率とペイオフレシオの関係

コツコツドカンはよくないと言われるが、それは勝率が高くても、それ以上にペイオフレシオが悪ければ資産は減っていくからである。逆に勝率が低くても、それ以上にペイオフレシオがよければ資産は増えていく。

損小利大はいいとよく言われるが、ペイオフレシオがよくても、それ以上に勝率が低ければ資産は減っていく。逆にペイオフレシオが悪くても、それ以上に勝率が高ければ資産は増えていくのである。大事なのは勝率とペイオフレシオの兼ね合いである。

一般的には勝率が高ければペイオフレシオは悪く、勝率が低ければペイオフレシオはよいと信じられている。そこで、ランダムウォークのデータを作成して、勝率とペイオフレシオの関係を調べてみる。

その前に、どのような関係にあるかを予想してみる。

一般に信じられている考えに基づくと、

平均利益 / 平均損失 = 負ける率 / 勝つ率

となるだろう。

これを整理すると、

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

となる。

そこで

勝率 = a * (1 / (ペイオフレシオ + 1)) + b

というモデルを作成し、ペイオフレシオでうまく勝率を予測できるか見てみる。特に理由がなければ、a(傾き)は1、b(切片)は0になるはずである。

先ず、ペイオフレシオを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)

そしてペイオフレシオとそれに対応する勝率の関係を調べる。すると、以下のような結果になった。

ちょっと分かりにくいが、実際の勝率とペイオフレシオを元に予測した勝率はほぼ一致しており、2本の線に見えるのは上が買いの場合の勝率、下が売りの場合の勝率である。わずかに買いの勝率が売りの勝率より高いことが分かる。

さて、傾きが1、切片が0であることを期待していたのだが、わずかに違う。誤差とするには少し大きすぎるように思うが、なぜこうなるかは分からない。

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

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

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

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

サンプルプログラム

○以下のコマンドを「IPython console」にコピー&ペーストして「Enter」キーを2回押す。

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

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

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

popt, pcov = curve_fit(func, payoff_ratio_long, wp_long)
a_long = popt[0]
b_long = popt[1]
wp_long_pred = a_long * (1 / (1 + payoff_ratio_long))  + b_long
popt, pcov = curve_fit(func, payoff_ratio_short, wp_short)
a_short = popt[0]
b_short = popt[1]
wp_short_pred = a_short * (1 / (1 + payoff_ratio_short))  + b_short
ax=plt.subplot()
plt.plot(payoff_ratio_long, wp_long, label='wp_long')
plt.plot(payoff_ratio_long, wp_long_pred, label='wp_long_pred')
plt.plot(payoff_ratio_short, wp_short, label='wp_short')
plt.plot(payoff_ratio_short, wp_short_pred, label='wp_short_pred')
plt.title('Winning Percentage and Payoff Ratio')
plt.xlabel('Payoff Ratio')
plt.ylabel('Winning Percentage')
plt.xlim(0, 9)
plt.ylim(0, 1)
plt.text(0.1, 0.9, 'Long', transform=ax.transAxes)
plt.text(0.1, 0.85, 'Slope = ' + str(a_long), transform=ax.transAxes)
plt.text(0.1, 0.8, 'Intercept = ' + str(b_long), transform=ax.transAxes)
plt.text(0.1, 0.7, 'Short', transform=ax.transAxes)
plt.text(0.1, 0.65, 'Slope = ' + str(a_short), transform=ax.transAxes)
plt.text(0.1, 0.6, 'Intercept = ' + str(b_short), transform=ax.transAxes)
plt.legend(loc="upper right")
plt.savefig('wp_por.png', format='png', dpi=150)
plt.show()
plt.close()
(2016/12/13更新)

コメント

非公開コメント