Python&Colab:銘柄間の相関を算出する(ピアソン、スピアマン、ケンドール)

Python&Colab:銘柄間の相関を算出する(ピアソン、スピアマン、ケンドール)

分散投資をする際によく用いられる「相関」を、Google Colaboratory(Python)で算出する方法の備忘録。以下を行った。

・TA-Libでピアソンの積立相関係数
・Scipy でスピアマンの順位相関係数
・Scipy でケンドールの順位相関係数
・Plotly でヒートマップを作成
・Plotly で3D の Surfaceグラフを作成

Google Colab:銘柄間の相関を算出する(ピアソン、スピアマン、ケンドール)

  1. 必要なモジュールをインストールと読み込み
    1. Plotly と TA-Libのインストール
    2. 必要なモジュールを読み込む
  2. データの取得
  3. TA-Lib でピアソンの積立相関係数を算出する
  4. Scipy でスピアマンの順位相関係数を算出する
  5. Scipy でケンドールの順位相関係数を算出する
  6. おまけ:全体の相関係数の推移を調べる

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銘柄名
EURUSDDEXUSEUU.S. / Euro Foreign Exchange Rate
GBPUSDDEXUSUKU.S. / U.K. Foreign Exchange Rate
USDJPYDEXJPUSJapan / U.S. Foreign Exchange Rate
USDCHFDEXSZUSSwitzerland / U.S. Foreign Exchange Rate
AUDUSDDEXUSALU.S. / Australia Foreign Exchange Rate
USDCADDEXCAUSCanada / U.S. Foreign Exchange Rate
NZDUSDDEXUSNZU.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()
TA-Lib CORREL 算出結果

目次へ

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

ピアソンの相関係数 ヒートマップ pearson correlation heatmap

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グラフを作成する

ピアソンの相関係数 surfaceグラフ pearson correlation

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()
スピアマンの相関係数 算出結果

目次へ

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

スピアマンの相関係数 ヒートマップ spearman correlation heatmap

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グラフを作成する

スピアマンの相関係数 Surfaceグラフ spearman correlation

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()
ケンドールの相関係数 算出結果

目次へ

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

ケンドールの相関係数 ヒートマップ kendall correlation heatmap

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グラフを作成する

ケンドールの相関係数 surfaceグラフ kendall correlation

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.おまけ:全体の相関係数の推移を調べる

  1. データの構造{ symbol1: { symbol2: { Dates: values } } }
  2. ここまでグラフ化したのはひとつのsymbol1 ✕ すべてのsymbol2 ✕ Date ✕ values
  3. すべての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()
平均した相関係数 算出結果 mean correlation

目次へ

全体の相関の推移をヒートマップで確認する

完璧ではないが、ヒートマップを何十枚も見比べる必要はなくなる。

平均した相関係数 ヒートマップ mean correlation heatmap

このグラフをみると、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 ) ) 

目次へ

参考

ピアソン、スピアマン、ケンドールの相関係数の違いは、以下がわかりやすかった。

Back to Top

最高のトレード環境を実現する「サクソバンク証券」

ボクが唯一つかっている取引会社です。

世界中のほとんどの市場に対応していて、日本株をCFDで取引すれば個別株とFXの損益を通算することもできます。何よりも、ひとつの口座に入金するだけですべての銘柄を取引できるのが本当に便利。

SaxoTraderGO
  • 「FX口座」150以上の通貨ペア
  • 「株価指数CFD口座」約250種類
  • 「個別株CFD口座」日米中など世界22カ国・34市場
  • 「バラエティCFD口座」債券やVIX、商品など約100種類
  • MT4にも対応!

Investment Tech Hack

Sorry... doesn't support your browser

To get the best possible experience using our site we recommend that you upgrade to a modern web browser. Investment Tech Hackではご利用中のブラウザサポートはしていません。
Internet Explorerのアップグレード行う、もしくはその他のブラウザを使用しての閲覧をお願いします。