yfinance, рассчитаем логарифмические доходности, построим гистограмму распределения с наложенной теоретической кривой Гаусса и проведем строгий статистический тест Шапиро-Уилка (scipy.stats.shapiro) для проверки гипотезы о нормальности.Введение в анализ распределения
В количественном анализе (Quantitative Finance) предположение о нормальном распределении доходностей активов лежит в основе многих классических моделей, включая портфельную теорию Марковица и расчет стоимости под риском (VaR). Однако реальные финансовые рынки характеризуются «тяжелыми хвостами» (fat tails) и асимметрией.
Перед тем как анализировать структуру временного ряда с помощью сложных методов, таких как Поиск ценовых паттернов с помощью Dynamic Time Warping (DTW) в Pandas или проводить Расчет показателя Херста (Hurst Exponent) для BTC/USDT на Python, кванту необходимо оценить базовые статистические свойства активов. Это критически важно при оценке рисков и расчете таких метрик, как в статье про Расчет Information Ratio, Alpha и Beta к Bitcoin на Python, где классические формулы часто неявно предполагают нормальность распределения. В этом руководстве мы разберем, как построить диаграмму распределения доходностей и провести строгий статистический тест Шапиро-Уилка на Python.
Исходный код
Ниже представлен готовый скрипт на Python, который загружает исторические данные индекса S&P 500 (SPY), рассчитывает логарифмические доходности, выполняет тест Шапиро-Уилка и строит визуализацию распределения в сравнении с идеальной нормальной кривой.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as stats
import yfinance as yf
# 1. Загрузка исторических данных
ticker = 'SPY'
data = yf.download(ticker, start='2020-01-01', end='2023-12-31')
# Вычисляем логарифмические доходности
data['Log_Returns'] = np.log(data['Adj Close'] / data['Adj Close'].shift(1))
returns = data['Log_Returns'].dropna()
# 2. Тест Шапиро-Уилка на нормальность
# Нулевая гипотеза (H0): данные распределены нормально
shapiro_stat, p_value = stats.shapiro(returns)
print(f"Статистика теста Шапиро-Уилка: {shapiro_stat:.6f}")
print(f"p-value: {p_value:.6e}")
alpha = 0.05
if p_value > alpha:
print("Вывод: Распределение близко к нормальному (не отклоняем H0)")
else:
print("Вывод: Распределение НЕ является нормальным (отклоняем H0 на уровне значимости 5%)")
# 3. Визуализация распределения доходностей
plt.figure(figsize=(10, 6))
# Построение гистограммы фактических доходностей
count, bins, ignored = plt.hist(returns, bins=50, density=True, alpha=0.6, color='royalblue', edgecolor='black', label='Фактические доходности')
# Построение теоретической кривой нормального распределения
mu, std = stats.norm.fit(returns)
xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 100)
p = stats.norm.pdf(x, mu, std)
plt.plot(x, p, 'r-', linewidth=2, label=f'Нормальное распределение\n(mu={mu:.4f}, std={std:.4f})')
# Оформление графика
plt.title(f'Распределение доходностей {ticker} vs Нормальное распределение', fontsize=14)
plt.xlabel('Логарифмическая доходность', fontsize=12)
plt.ylabel('Плотность вероятности', fontsize=12)
plt.legend(loc='upper right')
plt.grid(True, linestyle='--', alpha=0.5)
# Добавление результатов теста на график
test_results_text = f'Тест Шапиро-Уилка:\nStat = {shapiro_stat:.4f}\np-value = {p_value:.2e}\nНормальность: {"Да" if p_value > alpha else "Нет"}'
plt.text(0.05, 0.95, test_results_text, transform=plt.gca().transAxes, fontsize=10,
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
plt.tight_layout()
plt.show() Разбор параметров
stats.shapiro(returns): Функция из библиотекиscipy.stats, которая вычисляет статистику теста Шапиро-Уилка и соответствующее значениеp-value. Это один из наиболее мощных критериев проверки на нормальность для непрерывных распределений.p_value: Вероятность получить наблюдаемые (или еще более экстремальные) результаты при условии, что нулевая гипотеза о нормальности верна. Еслиp_value < 0.05, мы отвергаем гипотезу о нормальности.stats.norm.fit(returns): Метод максимального правдоподобия, который оценивает параметры среднего значения (mu) и стандартного отклонения (std) для построения теоретической кривой Гаусса поверх нашей гистограммы.np.log(data['Adj Close'] / data['Adj Close'].shift(1)): Расчет логарифмических доходностей. В отличие от простых доходностей, логарифмические доходности обладают свойством аддитивности во времени и лучше подходят для статистического моделирования.
Как запустить
Для запуска данного скрипта вам понадобятся установленные библиотеки для анализа данных и визуализации. Вы можете установить их одной командой через терминал:
pip install numpy pandas matplotlib scipy yfinance После установки запустите скрипт в вашей среде разработки (например, VS Code, PyCharm или Jupyter Notebook). Скрипт автоматически загрузит актуальные котировки, проведет расчеты, выведет результаты теста в консоль и отобразит интерактивный график распределения.




