Pythonでヒストリカルボラティリティの計算

以前、「Rでヒストリカルボラティリティの計算」で、Rを使用してヒストリカルボラティリティを計算してみた。

今回は、pythonで行ってみる。速度など、細かい点は気にしていないので改善の余地は多々ある。
以下、前提。

標準偏差の期間は20日、年換算時に使用する1年間の日数は250日として計算。
標準偏差は、不偏推定量ではなく、標本統計量で計算。

ヒストリカルボラティリティ(HV)計算メソッドは下記。

def getHV(stockObjListDict, period):
    #価格用numpy配列の準備
    priceDataList = np.array([])

    #入力引数から価格データ(終値)を取り出す(日付の降順で取得)
    loopNum = 0
    for keyDate, stockObj in sorted(stockObjListDict.items(), reverse=True):
        print keyDate, stockObj
        priceDataList = np.append(priceDataList, stockObj["close"])
        loopNum += 1

    #価格(終値)の前日比を求める
    priceDataListShifted = shift(priceDataList, -1, cval=np.NaN) #scipyのshift関数を使用して前日データのリストを取得
    priceDataListRatio   = priceDataList/priceDataListShifted

    #価格の前日比の分散の平方根をとり(標準偏差)、それにルート250をかけて年換算する
    result = pd.rolling_std(priceDataListRatio,window=20, ddof=False)*np.sqrt(250)*100 #「ddof=False」を指定し、標本統計量で計算する
    print "result =",result
    
    #rolling_std関数では、ndarrayを20日ずらしてしまうので、先頭の19個のNanを後方にずらす
    result = np.roll(result, -19)
    print "np.roll(result, -19) =",result
    
    return result

入力データ(stockObjListDict)は次の形式のディクショナリ。
データは「8604 野村ホールディングス」のものを使用。

OrderedDict(
[
('20161027', {u'high': 501.5, u'open': 491.1, u'trade_day': datetime.date(2016, 10, 27), u'low': 490.3, u'close': 501.3}),
('20161026', {u'high': 496.0, u'open': 493.9, u'trade_day': datetime.date(2016, 10, 26), u'low': 487.1, u'close': 494.5}),
('20161025', {u'high': 496.4, u'open': 489.7, u'trade_day': datetime.date(2016, 10, 25), u'low': 489.0, u'close': 494.4}),
('20161024', {u'high': 492.7, u'open': 492.4, u'trade_day': datetime.date(2016, 10, 24), u'low': 485.3, u'close': 486.6}),
・・・・・・

次のコードを実行した段階での結果が期待通りにはならなかった。

result = pd.rolling_std(priceDataListRatio,window=20, ddof=False)*np.sqrt(250)*100

期待値は、最初の19個の「nan」が存在しなくて、23.45158321から開始するものだったが、pandasのrolling_stdでは、そうはしてくれないようで、次のようになってしまった。

result = [ nan nan nan nan nan
nan nan nan nan nan
nan nan nan nan nan
nan nan nan nan 23.45158321
27.60455748 27.82368286 27.90660346 30.73291795 34.8071921
33.51431521 32.61410896 33.47891358 33.40454207 33.37327314
33.33776824 33.62421616 33.67834049 33.96221145 33.65715888
34.6598853 34.68606244 32.89762178 34.80696789 32.70979402

・・・・・・・・・・

そのため、次のコードを実行。

result = np.roll(result, -19)

これにより先頭のnanを後方にずらした。
※)shift関数を使用したら値が全てnanになってしまったので、rollを使用した。理由は分からなかったが、とりあえず放置。

最終的に得られた結果は下記。

np.roll(result, -19) = [ 23.45158321 27.60455748 27.82368286 27.90660346 30.73291795
34.8071921 33.51431521 32.61410896 33.47891358 33.40454207
33.37327314 33.33776824 33.62421616 33.67834049 33.96221145
33.65715888 34.6598853 34.68606244 32.89762178 34.80696789
32.70979402 33.02911553 33.33927726 33.07482384 30.7365178

・・・・・・・・・・