トレンドを理解する

日本経済と日経平均株価

Fred(セントルイス連銀サイト)のデータベースからは1949年からの日経平均株価が手に入る。

戦後、日本は戦後復興期、高度経済成長期、安定成長期、ブラックマンデーの余波を受け、バブル経済を経験し、またインターネットバブル、サブプライムショックなど数々の局面を乗り越えてきた。

そのような状況で、1949年以降の価格データを同一のものとして扱うと、株式市場、日本経済の実態を十分に把握できない。

そこでデータの期間を内閣府の景気基準日を用いて幾つかの景気循環期に分けて分析してみよう。

景気循環期とその期間を表にまとめた。

現在内閣府公表の景気循環期は15期あり、1つの循環期は景気拡張期と後退期に分けられている。

本資料ではそれを適時アレンジして用いている。

循環期 景気 期間 始点 終点
1,2 戦後復興期(recover) 1949/5/16 1954/11/30
3,4,5,6 高度経済成長期(growth) 1954/12/1 1971/12/31
7,8,9,10 安定期(stable) 1972/1/1 1986/11/30
11 バブル経済期(bubble) 1986/12/0 1993/10/31
12,13,14,15 経済変革期(reform) 1993/11/1 現在  

景気循環期の日経平均株価の年間変化率の算出   それぞれの循環期の日経平均株価の年率換算した変化率を計算してみよう

In [1]:
states=['recover','growth','stable','bubble','reform','now']
dates=["1949/5/16","1954/12/1",'1972/1/1',"1986/12/1","1993/11/1","2016/9/30"]
print(states)
['recover', 'growth', 'stable', 'bubble', 'reform', 'now']
In [2]:
print(dates)
['1949/5/16', '1954/12/1', '1972/1/1', '1986/12/1', '1993/11/1', '2016/9/30']
In [4]:
import pandas_datareader.data as web
import numpy as np
end='2017/7/31'
n225 = web.DataReader("NIKKEI225", 'fred',"1949/5/16",end).NIKKEI225
print('rate of change')
for i in range(len(dates)-1):
    ave=n225[dates[i]:dates[i+1]].pct_change().mean()*250
    print(states[i],': %2.2f %;'%(ave*100))
print 
print('volatility')
for i in range(len(dates)-1):
    vol=np.log(n225[dates[i]:dates[i+1]]).diff().std()*np.sqrt(250)
    print(states[i],': %2.2f %;'%(vol*100))
rate of change
recover : 13.71 %;
growth : 13.47 %;
stable : 13.48 %;
bubble : 3.49 %;
reform : 2.16 %;
volatility
recover : 22.99 %;
growth : 14.45 %;
stable : 12.64 %;
bubble : 22.82 %;
reform : 23.54 %;

結果の解釈

戦後復興期(recover)が14%、高度経済成長期(growth)が13%、安定期(stable)が13%と日経平均株価の変化率は大きな違いがない。

一方、バブル崩壊を含むバブル経済期(bubble)が3%、経済変革期(reform)においては2%と非常に低い。

また、価格の変動性の目安であるボラティリティ(250日換算の対数収益率の標準偏差)は高度経済成長期と安定期においては13-14%程度であるのに対して、

それ以外の戦後復興期、バブル経済期、経済変革期という混乱をともなう期間においては23-24%程度と非常に高くなっている。

プログラムコードの解説 :リストを用いた配列の作成

5つの循環期の配列を構築する。

states=['recover','growth','stable','bubble','reform','now']

配列の先頭はstates[0]='recover'であり、配列の末尾はstates[5]='now'である。

同様に経済の循環期の始点の配列を作ることができる。

Dates=["1949/5/16","1954/12/1",'1972/1/1',"1986/12/1","1993/11/1","2016/9/30"]

これらの配列はPythonのデータ構造の1つであるリストを用して作られている

プログラムコードの解説 : 年間収益率の算出

変化率はpandasのpct_change関数を用いて日々の価格の変化を変化率に変換している。

それをmean関数を用いて平均し、年間の変化率に換算するために250倍している。

for i in range(len(dates)-1):

ave=n225[dates[i]:dates[i+1]].pct_change().mean()*250

print(states[i],': %2.2f %;'%(ave*100))


プログラムコードの解説 : ボラティリティの算出

価格の対数を取るにはnampyのlog関数を用いている

pandasのdiff関数を用いて対数価格の差分を取って対数収益率としている。

std関数を用いてそれらの標準偏差を計算している

numpyのsqrt関数を用いて1日の標準偏差を250日分に修正している。

print('volatility')

for i in range(len(dates)-1):

  vol=np.log(n225[dates[i]:dates[i+1]]).diff().std()*np.sqrt(250)

  print(states[i],': %2.2f %;'%(vol*100))

グラフを用いた長期トレンドの把握

matplotlibにはいろいろな機能が備わっているので、線グラフ上に景気循環期の配列情報を表示することで、景気循環期と日経平均株価のトレンドを直感的につかんでみよう

In [7]:
struct_break=[('1949/5/16','recv'),('1954/12/1','  growth'),
              ('1972/1/1','stable'),('1986/12/1','bubble'),('1991/3/1','      reform')]
In [8]:
%matplotlib inline
import matplotlib.pyplot as plt
fig=plt.figure(figsize=(12, 8))
g=fig.add_subplot(1,1,1)
n225.plot(ax=g,style='y-',linewidth=0.5)
plt.ylabel('N225 Index')
for date, label in struct_break:
    g.annotate(label,xy=(date, n225.asof(date)+1000),
        xytext=(date,n225.asof(date)+10000),
        horizontalalignment='left',verticalalignment='top')
    g.set_xlim(['1947/1/1','2019/4/25'])

plt.title("Nikkei 225 and structural change")
Out[8]:
<matplotlib.text.Text at 0x7f9dd611b710>

結果の解釈 

このグラフからは日経平均株価が1983年以降急激に上昇し、1989年末にピークを付け、その後のバブル崩壊で株式市場のボラティリティが急激に上昇したように解釈できる しかし、この解釈には若干の問題がある。それを次節のデータの事前処理で詳しく説明しよう

プログラムコードの解説 :タプルを用いた配列の作成

内容の変更が必要ない配列はタプルにより作ることができる。

循環期とその始点からなる配列を作ってみよう。

struct_break=[('1949/5/16','recv'),('1954/12/1',' growth'), ('1972/1/1','stable'),('1986/12/1','bubble'),('1991/3/1',' reform')]

プログラムコードの解説 :グラフ表示のテクニック

matpoltlibは多種多様な描画ができる優れたグラフのライブラリーである。ここでは幾つかを利用している。

fig=plt.figure()

g=fig.add_subplot(1,1,1)

n225.plot(ax=g,style='y-',linewidth=0.5)

figure()でプロットに必要なウインドウの確保 サブプロットを追加

チャートの描画、axでサブプロットの場所の指定

stlyeで色を黄(y)に指定

for date, label in struct_break:

g.annotate(label,xy=(date, n225.asof(date)+1000),

   xytext=(date,n225.asof(date)+10000),

   horizontalalignment='left',verticalalignment='top')

g.set_xlim(['1947/1/1','2019/4/25'])

plt.title("Nikkei 225 and structural change")

データポイントにテキストを表示 asofで指定した日時のデータを取得 x軸の両端の措定 チャートのタイトルを表示

トレンド判定に必要なデータの事前処理

取引価格は取引の日時とその価値、または価値の上がり具合、下がり具合を示すトレンドを把握するには便利である。しかし、価格データを加工したほうがより便利な場合もある。その幾つかをここで紹介してみよう。  

1.価格自体 (p)  

2.価格の対数 (lnp)  

3.価格の変化率 (r)  

4.価格の対数の差 (lndp)  

5.価格の差 (dp)  

がある。

()の中はプログラム・コードに使う変数名である。  

価格

価格はいつどの時点で、どのような価格であったのか、また、何時から何時までを価格の上昇、または下落ととらえるべきなのかを把握するためには大変便利である。また、どれくらいの期間上下動を繰り返したのか、目視で周期的な性格があるのかを把握するためにも便利である。

価格の対数

価格の対数は大きく2つの解釈をもつ

1.瞬間的変化率d log(x)/dx=1/xからlog x=1/dxと表すことができ、対数が連続時間の変化率、または瞬間的変化率を表すと解釈することができる。  

2.弾力性:価格と売買高の関係を見るときに、価格の1%の変化に対する売買高の変化を価格の弾力性というが、これは と書けるので、対数を弾力性と理解することができる。

価格の動きの傾向を長期で見るときには対数をとってみる必要がある。そうすることで、変化率がどの価格帯でも同じスケールになる。  

価格の変化

2つ観測時期の異なる価格を比べることで、価格の動きを把握しようとすることがある。その際には、収益率、価格差、対数収益率などが用いられる。  

価格差

 今日は日経平均株価が100円上がったといえば、それは価格差のことである。 もっとも頻繁に用いられる変数の1つである。

その計算は単純であり、その特徴は線形性にある。しかし、価格差の意味するところはスケール変化の影響を受けやすい。

例えば時間が経過すると価格のレベルが大きく変わる日経平均株価のような場合には、「何月何日には1000円上がり、その1年後にも1000円上がった」と言ってもその意味するところは曖昧である。なぜなら日経平均株価が5000円の時の価格差1000円と10000円の時の価格差1000円ではその意味合いが違うからである。  

収益率 変化率(リターン) 

株式には配当があり、債券には金利収入があり、リターン、または収益率の計算にはキャピタルゲイン以外の収益が含まれていることがある。

しかし、多くの場合には単なる変化率(rate of return)である場合が多い。変化率は(Pt+1-Pt)/Pt = xである。  

対数収益率

対数収益率、対数差分は変化率の近似を与える。 変化率を(Pt+1-Pt)/Pt=1+xと変形し両辺の対数をとるととなる。

1.対数収益率はブラック‐ショールズのオプション価格モデルで用いられていることで知られている。経済成長が一定である、価格の動きが定常であると仮定すると、数学的に解析解が得やすく、多くの学術的モデルではこの形式が用いられる。スケール変化の自動平均補正機能をもっている。

2.変数Pt+1が変数Ptの周りで循環的な動きをしている場合、それをPt+1 = 1+PtまたはPt+1 = 1-/(1+x)Ptで表す。この2つの式の両辺の対数をとってその和を求めるとlog(Pt+1)-log(Pt)=0となる。リスクマネジメントの世界では対数収益率の平均値はゼロと考える。 短期的にはこれら3 つの変数は近似的に等しい

日経平均株価の長期トレンドの把握

前節のデータの事前処理の知識を生かして、日経平均株価の長期トレンド分析を試してみよう 対数価格表示  対数価格を用いてグラフを表示してみよう

In [9]:
import numpy as np
fig=plt.figure(figsize=(12, 8))
g=fig.add_subplot(1,1,1)
ln_n225=np.log(n225)               #numpyのlogを利用
ln_n225.plot(ax=g,style='y-',linewidth=0.5)

for date, label in struct_break:
    g.annotate(label,xy=(date, ln_n225.asof(date)),
        xytext=(date,ln_n225.asof(date)-0.75),
        horizontalalignment='left',verticalalignment='top')
    g.set_xlim(['1947/1/1','2019/4/25'])
plt.ylabel('log(N225 index)')
plt.title("Log Nikkei 225 index and structural change")
Out[9]:
<matplotlib.text.Text at 0x7f9dd2690a58>
In [10]:
import pandas_datareader.data as pdr
import numpy as np
for i in range(len(dates)-1):
    vol=np.log(n225[dates[i]:dates[i+1]]).diff().std()
    print(states[i],': %2.4f ;'%vol,)
recover : 0.0145 ;
growth : 0.0091 ;
stable : 0.0080 ;
bubble : 0.0144 ;
reform : 0.0149 ;

結果の解釈

対数価格表示のチャートと価格のチャートでは受けるイメージが全く違うのではないのだろうか? 

バブル経済期の始まる1986年末から日経平均株価のピークまでの期間を除くと、バブル崩壊前の日経平均株価はほぼ安定したリターンを達成している。

対数表示のグラフではこの辺を正確に描写している。長期チャートでは対数表示にする必要があるといわれる所以である

上記:目安の時期

戦後復興期(recover)

高度経済成長期(growth)

安定期(stable)

バブル経済期(bubble)

経済変革期(reform)

循環期 景気 期間 始点 終点 ror Vol std
1,2 戦後復興期(recover) 1949/5/16 1954/11/30 14% 23%  0.015
3,4,5,6 高度経済成長期(growth) 1954/12/1 1971/12/31 13% 14% 0.009
7,8,9,10 安定期(stable) 1972/1/1 1986/11/30 13% 13% 0.008
11 バブル経済期(bubble) 1986/12/0 1993/10/31 3% 23% 0.014
12,13,14,15 経済変革期(reform) 1993/11/1 現在   2% 24% 0.015

日中のリターンとオーバーナイトのリターン

 日経平均株価がバブル崩壊以降に下落を続け、未だにバブル期の最高値を更新できない事実はチャートを見れば一目瞭然である。

それは価格のチャートでも対数価格のチャートでも変わらない。しかし、この日経平均株価の新たな特徴を指数の対数を取ることでつかめたように、何か別の特徴が潜んでいないだろうか? 

日経平均株価は本当にバブル崩壊以降下落を続け戻り切れないのだろうか? 

そこで日経平均株価を分解することで新たな特徴をつかんでみよう。  

終値のチャートは価格や指数の大まかな傾向をつかむには適している。しかし、市場では多様な投資家が参加して、価格を形成している。

また、株式市場などは24時間取引がされているわけではなく、また、経済指標や、中央銀行の政策の決定の結果は日付と時刻を定めて発表される。

そのような発表には市場が閉じている間に行われるものも少なくない。

G7、G20などの会合は週末に行われ、月曜の朝の市場に大きな影響を与えることなどが多くみられる。

投資家は市場が開いているときにだけ活動を行っているわけではなく、市場が閉じている間でも得られた情報を分析し、次の取引に反映しようとしているのである。このような市場の参加者の行動をつかむ方法として、市場の寄り付きから引けまでの日中の価格の変化と、市場の引けから翌日の寄り付きまでのオーバーナイトの価格の変化を比べることがよく行われる。

それを行ってみよう

In [11]:
#Apple
plt.figure(figsize=(12,8))
analysis= web.DataReader("aapl", 'google',"1990/1/1",end)
analysis['intraday']=0#None
analysis['overnight']=0#None
c0=analysis.Close.iloc[0]    
for i in range(1,len(analysis)):
    o=analysis.iloc[i,0]#列0
    c=analysis.iloc[i,3]#列3
    analysis.iloc[i,5]=c-o#列6 Intraday
    analysis.iloc[i,6]=o-c0#列7 overnight
    c0=c
analysis.Close.plot(label='Close',linewidth=1)
analysis.intraday.cumsum().plot(label="intraday",linestyle=":")
analysis.overnight.cumsum().plot(label="overnight",linestyle='--',linewidth=1)
plt.legend()
plt.ylabel('PL or aapl')
plt.legend(loc='lower left')
Out[11]:
<matplotlib.legend.Legend at 0x7f9dd25dc2b0>

結果の解釈

グラフのy軸は収益、または日経平均株価を表している。バブル崩壊以降日経平均株価には3つの長期的な傾向がみられる。

1つは終値の下落である。

2つ目はオーバーナイトでの指数は上昇を続けているという事実である。

そして3つ目は日中の価格は下落を続けているということである.この原因は明らかにされていない。

最も有力な理由は短期の投資家が寄付きでポジションを建て、引けでポジションを閉じるという説である。

これは市場が効率的はなく、空売り等に制限が設けれている市場でみられる現象であるという説もあるが、確かではない。

その理由として、バブルの時期には日中もオーバーナイトでも指数は上昇し続けていた。

この時期の日中の指数の下落で顕著なのはブラックマンデーの時だけである。持ち合い株の解消、外国人投資家の動向も理由ではないだろうか?

参考のために米国のSP500を見てみよう 結果の解釈は任せます

In [12]:
#SP500
plt.figure(figsize=(12,8))
analysis= web.DataReader("SPY", 'google',"1993/1/29",end)
analysis['intraday']=0#None
analysis['overnight']=0#None
c0=analysis.Close.iloc[0]    
for i in range(1,len(analysis)):
    o=analysis.iloc[i,0]
    c=analysis.iloc[i,3]
    analysis.iloc[i,5]=c-o
    analysis.iloc[i,6]=o-c0
    c0=c
analysis.Close.plot(label='Close')
analysis.intraday.cumsum().plot(label='intraday',linestyle=':')
analysis.overnight.cumsum().plot(label='overnight',linestyle='--')
plt.legend()
plt.ylabel('PL or price')
Out[12]:
<matplotlib.text.Text at 0x7f9dd21999b0>

また、その他の参考としてダウ工業株価指数連動ETFのDIA

In [13]:
#NYダウ
plt.figure(figsize=(12,8))
analysis= web.DataReader("DIA", 'google',"1993/1/29",end)
analysis['intraday']=0#None
analysis['overnight']=0#None
c0=analysis.Close.iloc[0]    
for i in range(1,len(analysis)):
    o=analysis.iloc[i,0]
    c=analysis.iloc[i,3]
    analysis.iloc[i,5]=c-o
    analysis.iloc[i,6]=o-c0
    c0=c
analysis.Close.plot(legend='Close')
analysis.intraday.cumsum().plot(legend="intraday",linestyle=':')
analysis.overnight.cumsum().plot(legend="overnight",linestyle='--')
Out[13]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f9dd206f898>
In [ ]: