Python-Highchartsのドリルダウンでポートフォリオを可視化する

# Python-Highchartsのドリルダウンでポートフォリオを可視化する

投資信託のポートフォリオの可視化にPython-Highchartsを試してみました．
Python-HighchartsはJavaScriptの可視化ライブラリHighchartsのPythonのラッパーです．
Python-Highchartsを使うとインタラクティブに操作できるグラフを作成できます．

## インストール

Python-Highchartsをインストールします．

```python
pip install python-highcharts
```

なお，今回は，Python3.6.0です．

## 準備

はじめに，Python-Highchartsと今回使うライブラリをインポートします．

```python
from itertools import product  # 投資比率パターン生成用
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from highcharts import Highchart
%matplotlib inline
```

ここでは，伝統的な4つの資産，国内株式，国内債券，外国株式，外国債券のインデックスに連動する投資信託への資産配分を考えます．

- 国内株式インデックスファンド
- 国内債券インデックスファンド
- 外国株式インデックスファンド
- 外国債券インデックスファンド

事前にこれらの資産の時系列データから週次のリターンの平均と共分散行列を計算しておきます．(＊数値は一例です．用いた数値に一切責任は負いません．)

```python
asset_list = ['国内株式', '国内債券', '外国株式', '外国債券']
```

```python
mean = pd.Series([0.001487, 0.000283, 0.001905, 0.000723], index=asset_list, name='expected return')
mean
```

    国内株式    0.001487
    国内債券    0.000283
    外国株式    0.001905
    外国債券    0.000723
    Name: expected return, dtype: float64

```python
cov = pd.DataFrame([[7.95021e-04, -2.4461e-05, 6.06600e-04, 2.00937e-04],
                    [ -2.4461e-05, 8.485e-06, -2.1082e-05, -9.016e-06],
                    [  6.06600e-04, -2.1082e-05, 8.82778e-04, 2.15332e-04],
                    [  2.00937e-04, -9.016e-06, 2.15332e-04, 1.38414e-04]]
                   , index=asset_list, columns=asset_list)
cov
```

<div>

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>国内株式</th>
      <th>国内債券</th>
      <th>外国株式</th>
      <th>外国債券</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>国内株式</th>
      <td>0.000795</td>
      <td>-0.000024</td>
      <td>0.000607</td>
      <td>0.000201</td>
    </tr>
    <tr>
      <th>国内債券</th>
      <td>-0.000024</td>
      <td>0.000008</td>
      <td>-0.000021</td>
      <td>-0.000009</td>
    </tr>
    <tr>
      <th>外国株式</th>
      <td>0.000607</td>
      <td>-0.000021</td>
      <td>0.000883</td>
      <td>0.000215</td>
    </tr>
    <tr>
      <th>外国債券</th>
      <td>0.000201</td>
      <td>-0.000009</td>
      <td>0.000215</td>
      <td>0.000138</td>
    </tr>
  </tbody>
</table>
</div>

シャープレシオ（リスクフリーレートは考慮しない）も計算してみます．

```python
std = pd.Series(np.sqrt(np.diag(np.array(cov))), index=asset_list, name='expected volatility')
df = pd.concat([mean, std], axis=1)
df['sharpe ratio'] = mean / std
df.T
```

<div>

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>国内株式</th>
      <th>国内債券</th>
      <th>外国株式</th>
      <th>外国債券</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>expected return</th>
      <td>0.001487</td>
      <td>0.000283</td>
      <td>0.001905</td>
      <td>0.000723</td>
    </tr>
    <tr>
      <th>expected volatility</th>
      <td>0.028196</td>
      <td>0.002913</td>
      <td>0.029712</td>
      <td>0.011765</td>
    </tr>
    <tr>
      <th>sharpe ratio</th>
      <td>0.052738</td>
      <td>0.097154</td>
      <td>0.064116</td>
      <td>0.061454</td>
    </tr>
  </tbody>
</table>
</div>

4つの資産の平均と標準偏差をmatplotlibでプロットしてみます．

```python
plt.figure(figsize=(10, 6))
plt.scatter(std, mean, c=df.loc[:, 'expected return']/df.loc[:, 'expected volatility'], marker='o')
plt.grid(True)
plt.xlim(-0.005, 0.035)
plt.ylim(-0.00025, 0.002)
plt.xlabel('expected volatility')
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio')
#plt.savefig('.png')
```

![output_12_1.png](https://qiita-image-store.s3.amazonaws.com/0/193486/3acb60b3-f359-f6ab-1efe-c524782bc3ce.png)

## matplotlibで可視化する(比較用)

投資比率のパターンをたくさん作り，ポートフォリオの期待リターンと標準偏差を計算します．<br>
ランダムに作成した例とitertoolsを使った例を載せます．どちらか選択して実行してください．

- ランダムに投資比率のパターンを作ってみる

投資比率のパターンをたくさん作り，ポートフォリオの期待リターンと標準偏差を計算します．

```python
prets = []
pvols = []
weights_list = []  # highcharts用
for p in range(500):
    weights = np.random.randint(low=0, high=11, size=len(asset_list))
    weights = weights / np.sum(weights)
    weights_name = [[_i, _j] for _i, _j in zip(asset_list, weights)]  # highcharts用
    weights_list += [weights_name]  # highcharts用
    prets.append(np.sum(mean * weights))
    pvols.append(np.sqrt(np.dot(weights.T,np.dot(cov,weights))))
```

資産の組み合わせごとのリスク（標準偏差）と期待リターンをプロットし，色でシャープレシオの大きさを表します．

```python
plt.figure(figsize=(10, 6))
plt.scatter(pvols, prets, c=np.array(prets)/np.array(pvols), marker='o')
plt.grid(True)
plt.xlim(-0.005, 0.035)
plt.ylim(-0.00025, 0.002)
plt.xlabel('expected volatility')
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio')
```

![output_19_1.png](https://qiita-image-store.s3.amazonaws.com/0/193486/183382c2-6d93-e3c2-2884-9b62e46bc6ee.png)

- itertoolsのproductを使って投資比率のパターンを作ってみる

投資比率のパターンをたくさん作ります．

```python
weights = np.linspace(0, 1, 5)
weights = product(weights, repeat=4)
weights = pd.DataFrame(list(weights)[1:], columns=asset_list)
weights = weights.divide(weights.sum(axis=1), axis=0)
weights = weights.drop_duplicates()
```

ポートフォリオの期待リターンと標準偏差を計算します．

```python
prets = list((weights * mean).sum(axis=1))
pvols = []
for _num, _ix in enumerate(weights.index):
    w = weights.loc[_ix, :]
    pvols += [np.sqrt(np.dot(w.T, np.dot(cov, w)))]
```

```python
plt.figure(figsize=(10, 6))
plt.scatter(pvols, prets, c=np.array(prets)/np.array(pvols), marker='o')
plt.grid(True)
plt.xlim(-0.005, 0.035)
plt.ylim(-0.00025, 0.002)
plt.xlabel('expected volatility')
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio')
#plt.savefig('efficient_frontier_matplotlib.png')
```

![output_26_1.png](https://qiita-image-store.s3.amazonaws.com/0/193486/f7b6f818-4f79-1baf-bec9-e3b2b11b4e81.png)

## Highchartsで可視化する

Python-Highchartsを使うとインタラクティブで見栄えの良いグラフを作れます．

```python
options = {
    'title': {
        'text': 'リスクとリターン'
    },
    'xAxis': {
        'title': {
            'text': 'リスク'
        }
    },
    'yAxis': {
        'title': {
            'text': 'リターン'
        }
    },
    'chart': {
        'type': 'scatter',
    },
    'plotOptions': {
        'scatter': {
            'marker': {
                'radius': 4,
                'symbol': 'circle',
                'states': {
                    'hover': {
                        'enabled': True,
                        'lineColor': 'rgb(100,100,100)'
                    }
                }
            },
            'states': {
                'hover': {
                    'marker': {
                        'enabled': False
                    }
                }
            },
            'tooltip': {
                'headerFormat': '<b>{series.name}</b><br>',
                'pointFormat': 'risk :{point.x} <br> return:{point.y} '
            }
        }
    }
}
H = Highchart()
H.set_dict_options(options)
data = list(zip(pvols, prets))
weights_data = []
for i in range(len(weights)):
    weights_data += [{'x':data[i][0] ,'y': data[i][1], 'drilldown': 'portfolio'+str(i), 'name': 'portfolio'+str(i)}]
    # 'drilldown'と'name'はドリルダウン用
weights_data
H.add_data_set(weights_data, 'scatter', 'ポートフォリオ')
H
```

## 投資比率をドリルダウンで表示してみる

各リスク・リターンのプロットを実現する投資比率が分かるドリルダウンを加えてみます．

```python
# itertoolsを使ったとき用
weights_list = []
for _num, _ix in enumerate(weights.index):
    weights_name = [[_i, _j] for _i, _j in zip(asset_list, weights.loc[_ix, :])]
    weights_list += [weights_name]
```

```python
for i in range(len(weights)):
    H.add_drilldown_data_set(weights_list[i], 'pie', weights_data[i]['name'], name=weights_data[i]['name'])
```

```python
H
```

![hicharts2.gif](https://qiita-image-store.s3.amazonaws.com/0/193486/9e8f39fa-d95b-93f5-e954-9f00a05baa7d.gif)

動作しない環境などありましたら，教えてもらえると助かります．

## 参考

- [Highcharts公式サイト](https://www.highcharts.com/)
- [Jupyter notebookでHighcharts](https://qiita.com/driller/items/6ddf2f6f12a4e8044bc3)