켈리 기준을 사용하여 최적의 베팅 크기 결정

19338 단어 파이썬확률론

최적의 베팅 크기를 결정하는 방법?



본 기사에서는, Stefan Jasen씨에 의해 쓰여진 "Machine Learning for Algorithmic trading, 2nd edition"의 Chapter 5, the Kelly Criterion 에 대해 공부한 내용을 정리해 갑니다.

1. The optimal size of a bet



켈리 기준은 무한히 반복되는 베팅에서 자본 가치의 성장률을 극대화하는 베팅 크기(optimal $f$)를 찾는 것을 목표로 합니다. 이 켈리 기준의 사고방식을 수식으로 떨어뜨리면 다음과 같이 됩니다.
V_n = V_{0}(1+of)^m(1-f)^{n-m}\\
G = lim_{n\rightarrow\infty}\frac{1}{n}log\frac{V_n}{V_0}\\ 
  • $n$ = 베팅 총 횟수
  • $m$ = 이긴 횟수
  • $o$ = 1달러의 베팅을 이길 때 얻는 금액
  • $f$ = 현재 자본에 대한 베팅액의 비율
  • $G$ = 자본 성장률
  • $V_{n}$ = n번째 시간에 손에 있는 금액

  • 첫 번째 공식은 $n$번째 베팅 결과가 나온 시점에서 손에 남은 자본을 나타냅니다. 두 번째 방정식은 매번 베팅에서 자본 성장률을 의미하며 자본 성장률의 기하 평균의 로그를 취하는 형태입니다. 아래에서는 SymPy를 사용하여 optimal $f$를 계산합니다.
    
    #変数を定義
    share, odds, probability = sympy.symbols('share odds probability')
    
    #資産の成長率を表す式を定義
    G = probability*log(1+odds*share)+(1-probability)*log(1-share)
    
    #Gをshareに関して微分したもの=0を、shareに関して解く
    solve(diff(G,share),share)
    
    #出力(期待値/odds)
    [(odds*probability -(1- probability))/odds]
    
    #odds=1でshare=f,probability=p,G=yに書き換えた形
    f,p = sympy.symbols('f p')
    y = p*log(1+f)+(1-p)*log(1-f)
    solve(diff(y,f),f)
    
    #出力、これがfに関するG'=0の最適解f。
    2*p -1
    
    

    2. Get data



    이번에는 yahoofinance로부터 S&P500의 daily close price를 취득합니다. 기간은 2001-1-2~2020-12-31입니다. (사용하는 데이터는 Jansen씨와는 다릅니다.)
    
    import pandas as pd
    import numpy as np
    from numpy.linalg import inv
    from numpy.random import dirichlet
    from sympy import symbols,solve,log,diff
    from scipy.optimize import minimize_scalar,newton,minimize
    from scipy.integrate import quad
    from scipy.stats import norm
    import yfinance as yf
    import datetime 
    import matplotlib.pyplot as plt
    
    GetSPYinfo = yf.Ticker("SPY")
    #datetime.daterime()によりDateがDatetimeIndexとして認識される。
    #同時にそれ以外のカラムはデータとして認識される。
    startDate = datetime.datetime(2001,1,1)
    endDate = datetime.datetime(2021,1,1)
    df = GetSPYinfo.history(start = startDate, end = endDate)
    
    

    3. Compute returns and standard deviation



    이번에는 5년 이동평균과 표준편차를 계산하고 나서 평균치-2σ·평균치·평균치+2σ를 플롯해 나갑니다.
    
    #年リターンを計算
    Annual_returns =df_closed.resample('A').last().pct_change().dropna().to_frame('sp500')
    
    #リターンの5年移動平均および標準偏差を計算
    return_params = Annual_returns.rolling(5).agg(['mean','std']).dropna()
    
    #.sp500をつけることで、meanとstdが列ラベルとして認識される。
    return_params.sp500
    
    #データフレームreturn_paramsの平均ラベルの列を抜き出して、そこに、平均±2σの列を付け足す。
    return_params.sp500[['mean']]
    return_ci = (return_params.sp500[['mean']]
                   .assign(lower=return_params.sp500['mean'].sub(return_params.sp500['std'].mul(2)))
                   .assign(upper=return_params.sp500['mean'].add(return_params.sp500['std'].mul(2))))
    
    #各系列をプロット
    plt.plot(return_ci['mean'], color = 'blue')
    plt.plot(return_ci['lower'], color = 'orange')
    plt.plot(return_ci['upper'], color = 'green')
    
    labels = ['mean','mean-2sigma','mean+2sigma']
    plt.legend(labels)
    
    

    image.png

    4. Apply Kelly rule to a single asset



    The optimal size of a bet에서 자산 성장률 $G$를 나타내는 수식을 소개했습니다. 지금부터는 $E[G]$를 최대화하는 $f$를 scipy.optimize를 이용해 계산합니다.
    E[G] =\int log(1+fr)P(r)dr\Leftrightarrow \frac{d}{df}E[G] = \int_{-\infty}^{\infty}\frac{r}{1+fr}P(r)dr = 0
    
    #期待資本成長率を計算する関数を定義
    def norm_integral(f,mean,std):
        val, er = quad(lambda s:np.log(1+f*s)*norm.pdf(s,mean,std),mean-3*std, mean+3*std)
        return -val
    
    #期待資本成長率をfで偏微分する関数を定義
    def norm_dev_integral(f,mean,std):
        val,er = quad(lambda s:(s/(1+f*s))*norm.pdf(s,mean,std),m-3*std,mean+3*std)
        return val
    
    #期待資本成長率をfに関して最適化する関数を定義
    #最適化に用いる(偏微分に用いる)変数f以外の変数をargsで指定
    #bounds = [0,2]⇔ 掛け金の比率は0から200%に設定
    def get_kelly_share(return_params):
        solution = minimize_scalar(norm_integral,args=(return_params.sp500['mean'],
                                                       return_params.sp500['std']),
                                  bounds=[0,2],method='bounded')
        return solution.x
    
    #年率リターンのdfに新たな列fを追加
    Annual_returns['optimal f'] = return_params.apply(get_kelly_share, axis=1);
    
    #meanとstdをプロット
    return_params.plot(subplots=True,lw=2,figsize=(14,8));
    
    #パフォーマンス評価
    #[]だけだとpd.Seriesに変換され、[[]]だとpd.DataFrameに変換される。
    
    print(return_params);
    print(Annual_returns);
    y = (Annual_returns[['sp500']].assign(kelly=Annual_returns['sp500'].
                                     mul(Annual_returns['optimal f']))).dropna();
    
    #sp500の累積リターンとKelly Criterionを適用した際の累積リターンをプロット
    y.add(1).cumprod().sub(1).plot();
    
    

    좋은 웹페이지 즐겨찾기