分散投資をする際によく用いられる「相関」を、Google Colaboratory(Python)で算出する方法の備忘録。以下を行った。
・TA-Libでピアソンの積立相関係数
・Scipy でスピアマンの順位相関係数
・Scipy でケンドールの順位相関係数
・Plotly でヒートマップを作成
・Plotly で3D の Surfaceグラフを作成
Google Colab:銘柄間の相関を算出する(ピアソン、スピアマン、ケンドール)
1.必要なモジュールをインストールと読み込み
1-1.Plotly と TA-Libのインストール
Google Colab: Cell-1
# Plotly のインストール
!pip install plotly --upgrade
# TA-Lib のインストール
!curl -L http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz -O
!tar xzvf ta-lib-0.4.0-src.tar.gz
!cd ta-lib
!./configure --prefix=/usr
!make
!make install
!cd -
!pip install ta-lib
1-2.必要なモジュールを読み込む
Google Colab: Cell-2
import pandas as pd
import pandas_datareader.data as web
import numpy as np
import talib as ta
import scipy as sp
import plotly
import plotly.graph_objs as go
import plotly.figure_factory as ff
plotly.offline.init_notebook_mode( connected=True )
# google colabでplotlyを表示するにはこれが必要。
# グラフを書き出すセルごとに使用する
def enable_plotly_in_cell():
import IPython
from plotly.offline import init_notebook_mode
display(IPython.core.display.HTML('''
<script src="/static/components/requirejs/require.js"></script>
'''))
init_notebook_mode( connected=False )
2.データの取得
検証用のサンプルデータの取得は、pandas_datareader で FRED から。Stooq や yahoo はうまく動作しなかった。幸い、終値だけで事足りるので、FRED のデータで十分。
Google Colab: Cell-3
start = '2018/1/1'
symbols = { 'EURUSD': 'DEXUSEU'
, 'GBPUSD': 'DEXUSUK'
, 'USDJPY': 'DEXJPUS'
, 'USDCHF': 'DEXSZUS'
, 'AUDUSD': 'DEXUSAL'
, 'USDCAD': 'DEXCAUS'
, 'NZDUSD': 'DEXUSNZ' }
def get_prices( symbolsDict ,start ) :
fredCodeList = [ symbolsDict[symbol] for symbol in symbolsDict ]
df = web.DataReader( fredCodeList ,'fred' ,start )
#列名の変更、欠損値の対応
renameDict = { symbolsDict[symbol] : symbol for symbol in symbolsDict }
return df.rename( columns=renameDict ).ffill()[1:]
if __name__=='__main__' :
df = get_prices( symbols ,start )
データを取得するための、FRED 独自のコードは以下の通り。
通貨 | FREDコード | FRED銘柄名 |
EURUSD | DEXUSEU | U.S. / Euro Foreign Exchange Rate |
GBPUSD | DEXUSUK | U.S. / U.K. Foreign Exchange Rate |
USDJPY | DEXJPUS | Japan / U.S. Foreign Exchange Rate |
USDCHF | DEXSZUS | Switzerland / U.S. Foreign Exchange Rate |
AUDUSD | DEXUSAL | U.S. / Australia Foreign Exchange Rate |
USDCAD | DEXCAUS | Canada / U.S. Foreign Exchange Rate |
NZDUSD | DEXUSNZ | U.S. / New Zealand Foreign Exchange Rate |
3.TA-Lib でピアソンの積立相関係数を算出する
普段よく見かけれる相関係数はこれ。
Google Colab: Cell-4
df1 = df.copy()
np_price = { sym:np.array(df1.loc[: ,sym] ,dtype='f8') for sym in df1.columns }
cor_dict1 = {}
for sym_i in df1.columns :
raw = pd.DataFrame()
for sym_j in df1.columns :
correl = ta.CORREL( np_price[sym_i] ,np_price[sym_j] ,timeperiod=30 )
raw[ sym_j ] = correl
raw.index = df1.index
cor_dict1[ sym_i ] = raw
cor_dict1['EURUSD'].tail()

ピアソンの相関係数でヒートマップを作成する

Google Colab: Cell-5
target = 'EURUSD'
layout = go.Layout( title = ''
, autosize = False
, width = 1200
, height = 330 )
z1 = cor_dict1[ target ].drop( target ,axis=1 )
data = [ go.Heatmap( z = z1.T.as_matrix()
, y = z1.columns
, x = z1.index
, zmin = -1
, zmax = 1
,colorscale=[
[0 ,"rgb(255 ,0 ,0)"]
,[0.2 ,"rgb(255 ,235 ,59)"]
,[0.45 ,"rgb(255 ,255 ,255)"]
,[0.55 ,"rgb(255 ,255 ,255)"]
,[0.8 ,"rgb(255 ,235 ,59)"]
,[1.0 ,"rgb(255 ,0 ,0)"] ] ) ]
enable_plotly_in_cell()
plotly.offline.iplot(go.Figure(data=data ,layout=layout.update(dict(title=target))))
ピアソンの相関係数で3Dの surfaceグラフを作成する

Google Colab: Cell-6
target = 'GBPUSD'
layout = go.Layout( title = ''
, autosize = False
, paper_bgcolor = "#000"
, width = 1200
, height = 800
, scene = dict(
aspectmode = "manual"
, aspectratio = dict(x=1 ,y=2 ,z=0.5)
, xaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Symbol" ,nticks=15)
, yaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Date" ,type="date")
, zaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Correlation")
, camera = dict(eye=dict(x=2 ,y=1.25 ,z=1.5)) )
, font = dict(color="#fff") )
z1 = cor_dict1[ target ].drop( target ,axis=1 )
data = [ go.Surface( z = z1.as_matrix()
, y = z1.index
, x = z1.columns
, cmin=-1 ,cmax=1
, colorscale = "Jet"
, colorbar = dict(lenmode='fraction', len=0.5)
, contours = dict(x=dict(color="#fff") ,y=dict(color="#fff") ,z=dict(color="#fff")) ) ]
enable_plotly_in_cell()
plotly.offline.iplot( go.Figure( data=data ,layout=layout.update(dict(title=target)) ) )
4.Scipy でスピアマンの順位相関係数を算出する
投資における相関の算出は、ピアソンよりもスピアマンかケンドールの方が良いのではないかと考えている(大差はなさそうだけど)。今後、機会があれば検証してみたい。
Google Colab: Cell-7
length = 30
df1 = df.copy()
np_price = { sym:np.array(df1.loc[: ,sym] ,dtype='f8') for sym in df1.columns }
def calc_correl_spearmanr( np_ar1 ,np_ar2 ,timeperiod ) :
len1 = len(np_ar1)
len2 = len(np_ar2)
if len1==len2 :
result = []
for i in range( len1 ) :
if i < timeperiod-1 :
result.append(np.nan)
else :
a = i - (timeperiod-1)
b = i + 1
correlation ,pvalue = sp.stats.spearmanr( np_ar1[a:b] ,np_ar2[a:b] )
result.append( correlation )
return np.array( result )
else : raise
cor_dict2 = {}
for sym_i in df1.columns :
raw = pd.DataFrame()
for sym_j in df1.columns :
correl = calc_correl_spearmanr( np_price[sym_i] ,np_price[sym_j] ,timeperiod=30 )
raw[ sym_j ] = correl
raw.index = df1.index
cor_dict2[ sym_i ] = raw
cor_dict2['EURUSD'].tail()

スピアマンの相関係数でヒートマップを作成する

Google Colab: Cell-8
target = 'EURUSD'
layout = go.Layout( title = ''
, autosize = False
, width = 1200
, height = 330 )
z1 = cor_dict2[ target ].drop( target ,axis=1 )
data = [ go.Heatmap( z = z1.T.as_matrix()
, y = z1.columns
, x = z1.index
, zmin = -1
, zmax = 1
, colorscale=[
[0 ,"rgb(255 ,0 ,0)"]
,[0.2 ,"rgb(255 ,235 ,59)"]
,[0.45 ,"rgb(255 ,255 ,255)"]
,[0.55 ,"rgb(255 ,255 ,255)"]
,[0.8 ,"rgb(255 ,235 ,59)"]
,[1.0 ,"rgb(255 ,0 ,0)"] ] ) ]
enable_plotly_in_cell()
plotly.offline.iplot( go.Figure( data=data ,layout=layout.update(dict(title=target)) ) )
スピアマンの相関係数で3Dの Surfaceグラフを作成する

Google Colab: Cell-9
target = 'GBPUSD'
layout = go.Layout( title = ''
, autosize = False
, paper_bgcolor = "#000"
, width = 1200
, height = 800
, scene = dict(
aspectmode = "manual"
, aspectratio = dict(x=1 ,y=2 ,z=0.5)
, xaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Symbol" ,nticks=15)
, yaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Date" ,type="date")
, zaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Correlation")
, camera = dict(eye=dict(x=2 ,y=1.25 ,z=1.5)) )
, font = dict(color="#fff") )
z1 = cor_dict2[ target ].drop( target ,axis=1 )
data = [ go.Surface( z = z1.as_matrix()
, y = z1.index
, x = z1.columns
, cmin=-1 ,cmax=1
, colorscale = "Jet"
, colorbar = dict(lenmode='fraction', len=0.5)
, contours = dict(x=dict(color="#fff") ,y=dict(color="#fff") ,z=dict(color="#fff")) ) ]
enable_plotly_in_cell()
plotly.offline.iplot( go.Figure(data=data ,layout=layout.update(dict(title=target)) ) )
5.Scipy でケンドールの順位相関係数を算出する
スピアマンかケンドールかは、どちらでも大差がない(らしい)。
Google Colab: Cell-10
length = 30
df1 = df.copy()
np_price = { sym:np.array(df1.loc[: ,sym] ,dtype='f8') for sym in df1.columns }
def calc_correl_kendalltau( np_ar1 ,np_ar2 ,timeperiod ) :
len1 = len(np_ar1)
len2 = len(np_ar2)
if len1==len2 :
result = []
for i in range( len1 ) :
if i < timeperiod-1 :
result.append(np.nan)
else :
a = i - (timeperiod-1)
b = i + 1
correlation ,pvalue = sp.stats.kendalltau( np_ar1[a:b] ,np_ar2[a:b] )
result.append( correlation )
return np.array( result )
else : raise
cor_dict3 = {}
for sym_i in df1.columns :
raw = pd.DataFrame()
for sym_j in df1.columns :
correl = calc_correl_kendalltau( np_price[sym_i] ,np_price[sym_j] ,timeperiod=30 )
raw[ sym_j ] = correl
raw.index = df1.index
cor_dict3[ sym_i ] = raw
cor_dict3['EURUSD'].tail()

ケンドールの相関係数でヒートマップを作成する

Google Colab: Cell-11
target = 'EURUSD'
layout = go.Layout( title = ''
, autosize = False
, width = 1200
, height = 330 )
z1 = cor_dict3[ target ].drop( target ,axis=1 )
data = [ go.Heatmap( z = z1.T.as_matrix()
, y = z1.columns
, x = z1.index
, zmin = -1
, zmax = 1
, colorscale = [
[0 ,"rgb(255 ,0 ,0)"]
,[0.2 ,"rgb(255 ,235 ,59)"]
,[0.45 ,"rgb(255 ,255 ,255)"]
,[0.55 ,"rgb(255 ,255 ,255)"]
,[0.8 ,"rgb(255 ,235 ,59)"]
,[1.0 ,"rgb(255 ,0 ,0)"] ] ) ]
enable_plotly_in_cell()
plotly.offline.iplot( go.Figure( data=data ,layout=layout.update(dict(title=target)) ) )
ケンドールの相関係数で3Dの Surfaceグラフを作成する

Google Colab: Cell-12
target = 'GBPUSD'
layout = go.Layout( title = ''
, autosize = False
, paper_bgcolor = "#000"
, width = 1200
, height = 800
, scene = dict(
aspectmode = "manual"
, aspectratio = dict(x=1 ,y=2 ,z=0.5)
, xaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Symbol" ,nticks=15)
, yaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Date" ,type="date")
, zaxis = dict(color="#fff" ,linecolor="#fff" ,gridcolor="#eee" ,title="Correlation")
, camera = dict(eye=dict(x=2 ,y=1.25 ,z=1.5)) )
, font = dict(color="#fff") )
z1 = cor_dict3[ target ].drop( target ,axis=1 )
data = [ go.Surface( z = z1.as_matrix()
, y = z1.index
, x = z1.columns
, cmin=-1 ,cmax=1
, colorscale = "Jet"
, colorbar = dict(lenmode='fraction', len=0.5)
, contours = dict(x=dict(color="#fff") ,y=dict(color="#fff") ,z=dict(color="#fff")) ) ]
enable_plotly_in_cell()
plotly.offline.iplot(go.Figure(data=data ,layout=layout.update(dict(title=target))))
6.おまけ:全体の相関係数の推移を調べる
- データの構造
{ symbol1: { symbol2: { Dates: values } } }
- ここまでグラフ化したのは
ひとつのsymbol1 ✕ すべてのsymbol2 ✕ Date ✕ values
すべてのsymbol1 ✕ すべてのsymbol2 ✕ Date ✕ values
をひとつのグラフで確認したい
symbol1 の平均をつくることで、近いものを実現したい。
Google Colab: Cell-13
cor_avg1 = pd.DataFrame()
for sym in cor_dict1 :
raw = cor_dict1[ sym ]
cor_avg1[ sym ] = raw.loc[ : ,raw.columns != sym ].mean( axis=1 )
cor_avg1.tail()

全体の相関の推移をヒートマップで確認する
完璧ではないが、ヒートマップを何十枚も見比べる必要はなくなる。

このグラフをみると、9月ごろに全体の相関が強くなったことがわかる。リスクオフになるようなちょっとした金融危機が起きた可能性があると考えられる。
Google Colab: Cell-14
title = '全体の相関係数の推移'
layout = go.Layout( title = ''
, autosize = False
, width = 1200
, height = 330 )
z1 = cor_avg1
data = [ go.Heatmap( z = z1.T.as_matrix()
, y = z1.columns
, x = z1.index
, zmin = -1
, zmax = 1
, colorscale=[
[0 ,"rgb(255 ,0 ,0)"]
,[0.2 ,"rgb(255 ,235 ,59)"]
,[0.45 ,"rgb(255 ,255 ,255)"]
,[0.55 ,"rgb(255 ,255 ,255)"]
,[0.8 ,"rgb(255 ,235 ,59)"]
,[1.0 ,"rgb(255 ,0 ,0)"] ] ) ]
enable_plotly_in_cell()
plotly.offline.iplot( go.Figure( data=data ,layout=layout ) )
参考
ピアソン、スピアマン、ケンドールの相関係数の違いは、以下がわかりやすかった。
数分で検証できる!「Google Colab のテンプレート」をプレゼント
この記事を含め、過去に紹介してきた Google Colab のファイルをそのままプレゼントします。コピペする必要もなく、Googleドライブ上でまるごとコピーを作成して、そのまま使用することができます。
- 単利を含むバックテスト 日経平均・為替 4時間足
- 相関係数を算出してグラフを表示
- TA-Lib でテクニカル分析を算出してグラフを表示
- Ku-Chart を作成してグラフを表示
- EDINETから財務データを取得してスクリーニング
- 破産の確率を算出する
などなど!
必要なのはメールアドレスのご登録だけです!
※ 今後、Google Colab の記事を更新するごとに追加していく予定です
※ メルマガで行うのは、ほとんどがブログ更新のお知らせです。面白い、もしくは役に立つツールができたらお知らせすることもありますが、本業が忙しいのでせいぜい年に数回です。
※ 使用方法がわからない方はこの記事の最後にあるコメント欄からお問い合わせください。できる限りお答えします。コードの細かい部分も、ご質問いただければ出し惜しみせずお答えするつもりです!
数分で検証できる!「Google Colab のテンプレート」
誰でも、もっとも簡単に、さまざまな検証ができる Google Colaboratory のサンプル。