Расчет волатильности вручную и встроенные функции — это не одно и то же.

Может ли кто-нибудь помочь мне понять, где я ошибаюсь? Я не знаю, почему я получаю разную волатильность каждого столбца...

Это пример моего кода:

from math import sqrt
from numpy import around
from numpy.random import uniform
from pandas import DataFrame
from statistics import stdev

data = around(a=uniform(low=1.0, high=50.0, size=(500, 1)), decimals=3)
df = DataFrame(data=data, columns=['close'], dtype='float64')
df.loc[:, 'delta'] = df.loc[:, 'close'].pct_change().fillna(0).round(3)

volatility = []

for index in range(df.shape[0]):
    if index < 90:
        volatility.append(0)
    else:
        start = index - 90
        stop = index + 1
        volatility.append(stdev(df.loc[start:stop, 'delta']) * sqrt(252))

df.loc[:, 'volatility1'] = volatility
df.loc[:, 'volatility2'] = df.loc[:, 'delta'].rolling(window=90).std(ddof=0) * sqrt(252)

print(df)

      close   delta  volatility1  volatility2
0    10.099   0.000     0.000000          NaN
1    26.331   1.607     0.000000          NaN
2    32.361   0.229     0.000000          NaN
3     2.068  -0.936     0.000000          NaN
4    36.241  16.525     0.000000          NaN
..      ...     ...          ...          ...
495  48.015  -0.029    46.078037    46.132943
496   6.988  -0.854    46.036210    46.178820
497  23.331   2.339    46.003184    45.837245
498  25.551   0.095    45.608260    45.792188
499  46.248   0.810    45.793012    45.769787

[500 rows x 4 columns]

Большое спасибо!


person Hazan    schedule 21.09.2020    source источник


Ответы (1)


Необходимо внести три небольших изменения. Добавлены встроенные комментарии. 89 требуется с конечной точки включительно (в отличие от многих других вещей Python). ddof=1 необходим, потому что stdev использует его по умолчанию. Эта статья говорит о numpy std вместо stdev, но теория того, что делает ddof, остается прежней.

Кроме того, в будущем попробуйте изменить размер на что-то вроде 95. Вам не нужны другие 405 строк при отладке, и приятно видеть переход от 0/NaN к фактической волатильности, чтобы увидеть, что вам нужно 89, а не 90.

Разница между 0 и NaN все еще существует. Это результат того, что вы добавили 0 и прокрутили поведение по умолчанию. Я не был уверен, было ли это намеренно или нет, поэтому я оставил его.

from math import sqrt
from numpy import around
from numpy.random import uniform
from pandas import DataFrame
from statistics import stdev

data = around(a=uniform(low=1.0, high=50.0, size=(500, 1)), decimals=3)
df = DataFrame(data=data, columns=['close'], dtype='float64')
df['delta'] = df['close'].pct_change().fillna(0).round(3)

volatility = []

for index in range(df.shape[0]):
    if index < 89: #change to 89
        volatility.append(0)
    else:
        start = index - 89 #change to 89
        stop = index
        volatility.append(stdev(df.loc[start:stop, 'delta']) * sqrt(252))

df['volatility1'] = volatility
df['volatility2'] = df.loc[:, 'delta'].rolling(window=90).std(ddof=1) * sqrt(252) #change to ddof=1

print(df)
person noah    schedule 21.09.2020
comment
Благодарю вас! Не могли бы вы объяснить мне, почему мы начинаем с index - 89? Мы должны пропустить первую строку дельты в расчете? И почему volatility2 имеет значение в строке 89? Это должно быть NaN нет? - person Hazan; 22.09.2020
comment
Python имеет индекс 0. поэтому 90-й элемент имеет индекс 89. Давайте используем окно 3 для демонстрации. Если вы находитесь в индексе 2, ваши 3 элемента равны 0,1 и 2. Если ваше окно равно 90, то по индексу 89 ваши 90 элементов равны 0,1,...,88 и 89. Вы заметите, что ваши 500 строк в вашем вопросе идут от 0-499. Вы не пропускаете первую строку дельты в расчете. Имеет ли это смысл сейчас? - person noah; 22.09.2020