正規分布からのズレを特定する流れ

# 1:概要
・トレードは必ず正規分布からのズレから生じる
・実データにおける正規分布からのズレを特定する方法を(GPTに）検討してもらった
・ズレの大きさの定量化から始まり、最終的にはズレているポイントまで特定できた


# 2:背景
正規分布からのズレがトレードにおけるαとなる。
しかし、そのαが実際にはどの程度存在しているか、まず知らなければ戦略も立てられない
そこで正規分布からのズレ具合を(GPTに）確認してもらった


# 3:正規分布からのズレを出す（数値情報）
まずは数値として、どれぐらい正規分布からズレいているか把握する

### ①：統計的検定（正規性検定）
「この分布は正規分布とどれだけ違うか」を調べるには、まず **正規性の検定（正規分布化どうかチェックする）** を行うのが一般的です。

:::note info
✅ 代表的な検定
Shapiro-Wilk検定
Kolmogorov-Smirnov検定
Anderson-Darling検定
Jarque-Bera検定
:::

これらは「正規分布からのズレ」を数値（統計量）として出してくれます。


### ②：KLダイバージェンス（情報量的なズレ）
ある分布 𝑃 と正規分布 Q の間の距離を測る指標として Kullback-Leibler (KL) ダイバージェンス を使うことができます。これは「PがQからどれだけズレているか」を％ではなく **「情報量の差」** で測る方法です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/45056a3c-7e96-44f3-b09c-3528aa16f06c.png)


### ③：ヒストグラムの差異から％ズレを評価
分布 P をヒストグラムにして、正規分布のヒストグラムと比べることができます。 **各ビンの差を合計** し、以下のように％を出す方法です
※ これは正規化された確率ヒストグラムで行うとよいです。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/84ecf7b1-94ff-4615-9baa-c68c996e6367.png)



# 4:日経平均で試した場合
### ①：正規性検定
:::note info
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/da183da4-7c9e-4213-869f-119e7f4d776b.png)
:::
→ **このデータは統計的にはほぼ正規分布と言ってよい結果です。** 


### ②：KLダイバージェンス
 **値：25.83** 
これは「真の分布と正規分布の情報的なズレ」を意味します。値が大きいほどズレが大きいですが、絶対的な解釈は難しいため、他の分布と比較して相対的に使います。


### ③：ヒストグラム差異による％ズレ
正規分布との絶対差（正規化ヒストグラムで）： **約25.83%** 
つまり、ヒストグラムの各ビンの合計的な差異が全体の約26％存在する、という意味になります。

### ※：25.83の解釈
あるビンでは、正規分布よりも実データの方が多く
別のビンでは、逆に正規分布の方が多く
…という **偏りや歪みの総合的なズレを全部足し合わせて、それが 理想的な正規分布の確率全体（100%）のうち25.83%に相当する** ということです。


:::note info 
実務的な解釈  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/624b4535-2c13-4133-90aa-3616c6deb6b2.png)
:::

意外にズレが大きい




# 5:正規分布からのズレを可視化する
数値だけだと分からないので、可視化する

### ①：ヒストグラムの可視化
:::note info

<details><summary>コード</summary>

```python
# ズレを塗るために実データと正規分布の密度差をプロット
plt.figure(figsize=(10, 6))

# 実データのヒストグラム（密度）
hist_p, bins = np.histogram(returns, bins=50, density=True)
bin_centers = (bins[1:] + bins[:-1]) / 2

# 正規分布の密度（同じビン中心で計算）
hist_q = stats.norm.pdf(bin_centers, mu, std)

# プロット
plt.plot(bin_centers, hist_p, drawstyle='steps-mid', label='Actual Returns', color='blue')
plt.plot(bin_centers, hist_q, linestyle='--', label='Fitted Normal', color='red')

# 差の部分を塗る
plt.fill_between(bin_centers, hist_p, hist_q, where=(hist_p > hist_q), color='orange', alpha=0.4, label='Actual > Normal')
plt.fill_between(bin_centers, hist_p, hist_q, where=(hist_p < hist_q), color='green', alpha=0.4, label='Normal > Actual')

plt.title('Distribution Comparison with Deviation Highlighted')
plt.xlabel('Daily Return')
plt.ylabel('Probability Density')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

```
</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/8969bcc8-6f49-433e-857f-8b6fb4ac9a5d.png)

中央が多くて、周辺で少なくなっているのが何となく分かる

:::



### ②：累積分布（CDF）での比較、尖度・歪度の可視化やQ-Qプロット

:::note info

<details><summary>コード</summary>

```python
# CDF（累積分布）の可視化
plt.figure(figsize=(15, 4))

# サブプロット1: CDF
plt.subplot(1, 3, 1)
sorted_returns = np.sort(returns)
cdf_empirical = np.arange(1, len(returns)+1) / len(returns)
cdf_normal = stats.norm.cdf(sorted_returns, mu, std)
plt.plot(sorted_returns, cdf_empirical, label='Empirical CDF', color='blue')
plt.plot(sorted_returns, cdf_normal, linestyle='--', label='Normal CDF', color='red')
plt.title('CDF Comparison')
plt.xlabel('Daily Return')
plt.ylabel('Cumulative Probability')
plt.legend()
plt.grid(True)

# サブプロット2: Q-Qプロット
plt.subplot(1, 3, 2)
stats.probplot(returns, dist="norm", plot=plt)
plt.title('Q-Q Plot')

# サブプロット3: 歪度・尖度の可視化（棒グラフ）
plt.subplot(1, 3, 3)
skewness = stats.skew(returns)
kurtosis = stats.kurtosis(returns, fisher=True)  # Fisher=True で 0 が正規分布の基準
bars = plt.bar(['Skewness', 'Kurtosis'], [skewness, kurtosis], color=['skyblue', 'lightcoral'])
plt.axhline(0, color='gray', linestyle='--')
plt.title('Skewness and Kurtosis')
plt.grid(True)

plt.tight_layout()
plt.show()


```
</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/d8e7b81c-a3cc-4f82-bd0c-ab89ccc49cf2.png)

今までの結果とは違って、ほとんど正規分布的に見える（逆に言えば、これでも25%はズレている）
:::


### ※：累積分布（CDF）での比較、尖度・歪度やQ-Qプロットの解釈

:::note info 
📊【1. CDF（累積分布関数）比較グラフ】
● 何を見ているか？
実際のデータが「ある値以下になる確率」を順に並べた線（青）
正規分布に従った場合の累積確率（赤い破線）

解釈
2本の線が重なっていれば → 正規分布に近い
ズレていれば → 分布の位置や形状が違う

今回の観察
真ん中付近はよく重なっている → 平均付近は正規的
両端（特に左端）でややズレ → 外れ値や裾野に**非正規性（fat tailsや偏り）**がある
:::


:::note info 
📊【2. Q-Qプロット（Quantile-Quantile Plot）】
● 何を見ているか？
実際のデータの分位点（何％目の値）と、正規分布の同じ分位点を比較したプロット
解釈
点が一直線上（45度線）に並べば → 正規分布と同じ形
端が曲がっていれば → 歪みや厚い尾（heavy tails）

今回の観察
中央付近は直線的 → 中央は正規的
両端がやや外れる → 外れ値の頻度が正規分布より多い（厚い尾）
:::


:::note info
📉【3. 歪度（Skewness）と尖度（Kurtosis）の棒グラフ】
● 何を見ているか？
データの「非対称性（歪み）」と「鋭さ（尖り具合）」を数値で表示

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/49492d38-ae71-4d40-8888-0b1fd4531592.png)

解釈
Skewness（歪度）：正なら右に長い尾 → リターンが大きく上に跳ねることが多い
Kurtosis（尖度）：正なら尖ってる → 外れ値が多い（リスク高め）

今回の観察
歪度も尖度も0よりやや上 → 軽く右に偏っていて、外れ値もやや多め
:::


📉全体の解釈
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/8ff8d558-b141-4e1f-acdd-8f50fae48d97.png)

GPT歪度の解釈間違ってない？


# どこが一番正規分布からズレているか特定する
### ①：正規分布からのズレ領域の特定

:::note info

<details><summary>コード</summary>

```python

# 各ビンごとのズレ率を計算（正規分布との絶対差 / 正規分布値）
bin_differences = hist_p_sp - hist_q_sp
bin_relative_diff = (bin_differences / hist_q_sp) * 100  # パーセント化
bin_relative_diff = np.round(bin_relative_diff, 2)

# ズレの大きい順にデータフレーム化
deviation_df = pd.DataFrame({
    "Bin Center": bin_centers_sp,
    "Actual Density": hist_p_sp,
    "Normal Density": hist_q_sp,
    "Difference (%)": bin_relative_diff
}).sort_values(by="Difference (%)", key=abs, ascending=False).reset_index(drop=True)

# 上位のズレ（絶対値が大きい）10件を表示
tools.display_dataframe_to_user(name="ズレの大きいビン上位10件", dataframe=deviation_df.head(10))

```
</details>


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/519c70eb-6e6b-4fec-9985-6667dcd81812.png)

解釈
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/5f9f4bf8-9e2e-4d03-873e-8a772940c504.png)

とりあえず大きそう（小並）
:::



### ②ズレの大きさを可視化：ズレが大きいビンの棒グラフ（上位10件）

:::note info

<details><summary>コード</summary>

```python

top_deviation = deviation_df.head(10)

plt.figure(figsize=(12, 6))
bars = plt.bar(top_deviation["Bin Center"], top_deviation["Difference (%)"], width=0.0015, color='orange')
plt.axhline(0, color='gray', linestyle='--')
plt.xlabel("Return Bin Center")
plt.ylabel("Difference (%) vs Normal Distribution")
plt.title("Top 10 Deviations Between Actual and Normal Distribution (S&P500)")
plt.grid(True)

# 差が正か負かで色を変える
for bar, diff in zip(bars, top_deviation["Difference (%)"]):
    bar.set_color('orange' if diff > 0 else 'green')

plt.tight_layout()
plt.show()

```
</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976724/96f8990b-c70e-47cf-a91f-af717ba2aa23.png)


解釈
 **特に-2〜-3%付近の下落が正規分布より「はるかに頻繁」に発生（最大で4500%以上の差！）** 
一方で、+2%付近の急騰も正規分布より多め
→ fat tails（厚い尾）を持つ分布であり、正規性を仮定するモデルはリスクを過小評価する可能性がある
:::


# まとめ
以上のような流れで正規分布からのズレを特定してきた。
実際にはもっと色々調査する必要はあるだろうが、差し当たっての正規分布からのズレ調査としては十分だろう。