技術メモ

役に立てる技術的な何か、時々自分用の覚書。幅広く色々なことに興味があります。

為替相場の値動きにウィナー過程を仮定するのはダメかもしれない

為替相場の値動きに本当にウィナー過程を当てはめていいんだろうか。
簡単に調べられそうだったので、ドル円相場で少し調べてみた。
結果から言うと、正規分布っぽくなくねって結論が出てしまった。

ウィナー過程…確率過程W_tにおいてW_{t+s} - W_tが平均0分散sの正規分布に従うような確率過程

為替データの取得

pandas_datareader

というライブラリを使えば、Web上の色々な情報を取ってくることができるらしい。
便利。
ドル円(USD/JPY)相場をとってくるにはパラメータを"DEXJPUS"とするようだ。
pandas-datareaderで株価や人口のデータを取得 | nkmk log

from pandas_datareader import data
start = datetime(2010,1,1)
end = datetime(2017,1,1)
usdjpy = data.DataReader("DEXJPUS","fred",start,end)

分析

分析では、2010年1月1日から2017年1月1日までの1日間隔の値動きを使った。
欠損値は除外した上で、1日の差分が正規分布に従うかどうかについて調べた。
正規性の検定にはシャピロウィルク検定を用いた。
pythonで正規性の検定【コロモゴロフスミルノフ検定(KS検定)】 - 技術メモ

結果

下の図は、青い線がヒストグラムKDE*1を表し、黒い線が正規分布にフィッティングしたものを表す。
f:id:swdrsker:20170711053739p:plain
p値は
7.15e-24
となって、正規分布じゃなくねって結論が出た。

見た目では、正規分布に比べると中心と裾にかけて広くなっていくような分布っぽい。
1分足とか1時間足で使えるデータが簡単に見つからなかったのでやってないが、それらでも試してみたい。

コード

from pandas_datareader import data, wb
from datetime import datetime
from math import isnan
from scipy import stats
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set_style("whitegrid")

start = datetime(2010,1,1)
end = datetime(2017,1,1)
usdjpy = data.DataReader("DEXJPUS","fred",start,end)

subs = zip(usdjpy["DEXJPUS"][:-1],usdjpy["DEXJPUS"][1:])
sublist = []
for i,j in subs:
    if isnan(i) or isnan(j):
        continue
    sublist.append(j - i)

print(stats.shapiro(sublist)[1])

sns.distplot(sublist,fit=stats.norm)
plt.title("dist of 2010-2017 USD/JPY price movement")
plt.show()

FXを始めて、金融工学の触りを学んで感じたこと

f:id:swdrsker:20170708233238p:plain
FXに興味が出てきて、バーチャルトレードで短期投資をしてたんだけど、10万円くらい負けてもうやめてやろうかと思った。
それで、負けん気というか、儲けてる奴は何をしてるんだろうと思って色々調べていると金融工学の分野に辿り着いてしまった。勉強していくうちに面白くなってきたので、FXも金融工学も素人だけど素人なりに調べたり考えたりしたことをメモする。

FXで儲けることとは

FXで儲けることは基本的には
「安く買って高く売る」
ことである。でもその中でも戦略がいくつかある。

  • 短期投資
  • 長期投資
    • 長期のトレンドで儲ける
    • 長期のスワップで儲ける

短期投資は10分後に為替がどうなるかを当てること、単純に当たったら儲かる。
テクニカル分析とか胡散臭い方法論は出回っているけれど、短期だとほとんどギャンブルだ。
相場が上がるか下がるかはほとんどランダムに近いからだ。

長期投資はその名の通り、長期(1週間〜数ヶ月)にわたって通貨を持つこと。
戦略は二種類に分かれる。短期投資と同じように上げ下げを当てる方法と、スワップと言って配当金みたいなものを目当てに儲ける方法。

金融工学の役割

金融工学がFXにどう影響するか

誤解されがちなのが、金融工学は将来の為替相場をきっちり当てるのが目標だと思われることがある。僕も勉強を始める前はそう思っていた。しかし、金融工学の立場ではむしろ値動きは不確定な要素だと受け入れた上で、いかに正しく期待値を計算するかというところに注力される。
さっきも言ったように5分後の値動きなんかは本当に誰にも予測がつかない。ここに金融工学が割り込む余地はない。

だからこそ、金融工学が貢献するのは長期投資の方だ。例えばスワップを目当てにする取引の場合、期待値とスワップの価格が釣り合っていないような通貨ペアを計算しローリスクで利益を生むようなポートフォリオを組み立てるといった応用例がある。
特に「将来X円で売る(買う)権利」自体を取引することがあってこれをオプションと言うが、このオプションの値段を決めたりあるいは自分に有利なオプションを組んだりするのが金融工学の役割である。

FXにおける金融工学の目的

金融工学の目的は大きくいってしまえば、
1.「リスク自体の価格の正当な評価」
2.「評価のズレから生まれる違いを利用して儲ける方法」
の2軸になっている。
すごく大きく分けたので、もう少し詳しく話すと。
1の中には金融商品の価格決定とか、法改正が金利に与える影響の推定とかがある
2の中には新しい金融商品・オプション商品の作成とか、リスクヘッジをしながらスワップで儲けるためのポートフォリオ作成とかがある。

例えば、有名なサブプライムローン問題なんかは土地価格の高騰が前提となっていた金融商品が、土地価格の高騰が止まってしまったことによって期待値と実際の価格に違いが出てしまった*1。そこに目を付けた金融屋さんがサブプライムローン空売りして儲け逃げしてしまった。これは1による正当な価格の評価がうまく機能せず、2のタイプの金融屋さんに痛いところを突かれた、ということになる。

まあでもこの2つの括りでおおむね間違いないだろう。
すなわち
「期待値を0にしよう」という方向性と
「期待値の差を利用して儲けよう」という方向性の
イタチごっこになってしまっているわけだ。
強固な暗号を考えることと暗号を破る方法を考える暗号理論に似ているとも言える。

金融工学の社会的貢献

でも暗号理論と違うところは、結局誰も幸せにならないんじゃないかということ。
暗号理論は暗号を作ることと破ることのイタチごっこにより、素人では簡単に破れない強固な暗号を生み出してきた。
今やブロックチェーンやクレジット決済などのセキュリティの分野で無くてはならないものになっている。
でも金融工学はどうだろうか。
結局誰が幸せになるんだろう。為替を取引するプレーヤは幸せになるとして、FXには直接関係ない人たちにどういう良い影響を及ぼせるんだろうか。
例えばさきほどのサブプライムローンの話では、目先のお金のない人にも家を買える夢を与えることができた。貢献があるとすればそういう事だろうか。しかし、一方でサブプライムローン問題を引き起こしたのも金融工学の功罪であり、金融工学に対する不信感は拭えない。

雑感

確率的な考え方は統計学と相性が良く、学問領域としては面白い。

*1:金融商品が複雑化しすぎて適切なプライシングができない状況だった

pythonで正規性の検定【コロモゴロフスミルノフ検定(KS検定)】

確率分布が正規分布に従うか調べたい、
二つの集団が同じ確率分布から得られたものか調べたい、
といった時に使うのが、コロモゴロフスミルノフ検定(Kolmogorov–Smirnov test)

コルモゴロフ–スミルノフ検定(コルモゴロフ–スミルノフけんてい、英: Kolmogorov–Smirnov test)は統計学における仮説検定の一種であり、有限個の標本に基づいて、二つの母集団の確率分布が異なるものであるかどうか、あるいは母集団の確率分布が帰無仮説で提示された分布と異なっているかどうかを調べるために用いられる。しばしばKS検定と略される。
1標本KS検定は、経験分布を帰無仮説において示された累積分布関数と比較する。主な応用は、正規分布および一様分布に関する適合度検定である。正規分布に関する検定については、リリフォースによる若干の改良が知られている(リリフォース検定)。正規分布の場合、一般にはリリフォース検定よりもシャピロ-ウィルク検定やアンダーソン-ダーリング検定の方がより強力な手法である。
2標本KS検定は、二つの標本を比較する最も有効かつ一般的なノンパラメトリック手法の一つである。これは、この手法が二つの標本に関する経験分布の位置および形状の双方に依存するためである。
wikipedia:コルモゴロフ-スミルノフ検定

pythonではscipyというライブラリを使う。

1標本の場合

from scipy import stats
stats.kstest(rvs, cdf, args=(), N=20, alternative='two-sided', mode='approx')

rvs:データor単語
cdf:累積分
args:分布の形状を指すパラメータ(必要に応じて)

p値はpvalueで取り出す。

試してみる

f:id:swdrsker:20170626042622p:plain:w500

の3つに対して、正確に分けられるかチェック。
正規分布のデータは正規分布だと、そうでないデータは正規分布ではないと判別してほしい。

x = stats.norm.rvs(size=500)
y = stats.cauchy.rvs(size=500)
z = stats.t.rvs(3,size=500)
print(stats.kstest(x,"norm").pvalue)
print(stats.kstest(y,"norm").pvalue)
print(stats.kstest(z,"norm").pvalue)
0.611401246262    #正規分布(>0.05)
8.59754489824e-11 #コーシー分布(<0.05)
0.0135550060406   #t分布(<0.05)

正規分布とそうでない分布がきちんと判別できていることがわかる。

【補足】KS検定 vs. シャピロ-ウィルク検定

正規性の検定に限っては、wikipediaに載っているようにシャピロウィルク検定が良いらしい。
幸いscipyで実装されているようだったので、試してみる。

  • 方法

性能を比較するため、サンプルサイズを25~500の間を25刻みで増やしていく。
それぞれの分布・サンプルサイズに対して40回のサンプリングを行い、得られたp値の平均値をプロットする。
どれくらいのサンプルサイズだと誤判別が起きないかを確認してみる。有意水準は95%とした。

1. コロモゴロフスミルノフ検定
f:id:swdrsker:20170626051248p:plain:w500
2. シャピロウィルク検定
f:id:swdrsker:20170626051304p:plain:w500
コーシー分布・t分布のどちらともが点線(5%)を下回っていれば判別できている(正規分布ではないと判断している)ということだが、シャピロウィルク検定はサンプルサイズが小さくてもよく判別できているといえる。
シャピロウィルク検定の場合サンプルサイズが100程度あれば十分かも。
また、どちらの検定でも正規分布なのに正規分布でないと判断してしまうことはなかった。

使ったコード

samplesize = range(25,525,25)
samplingnum = 40
xlist = []
ylist = []
zlist = []
for i in samplesize:
    xsampling = []
    ysampling = []
    zsampling = []
    for j in range(samplingnum):
        x = stats.norm.rvs(size=i)
        y = stats.cauchy.rvs(size=i)
        z = stats.t.rvs(3, size=i)
        xsampling.append(stats.shapiro(x)[1])
        ysampling.append(stats.shapiro(y)[1])
        zsampling.append(stats.shapiro(z)[1])
    xlist.append(sum(xsampling)*1.0/samplingnum)
    ylist.append(sum(ysampling)*1.0/samplingnum)
    zlist.append(sum(zsampling)*1.0/samplingnum)
plt.plot(samplesize,xlist, label="norm")
plt.plot(samplesize,ylist, label="cauchy")
plt.plot(samplesize,zlist, label="t (3)")
plt.plot(samplesize,[0.05 for i in range(len(samplesize))], "--", color="black")
plt.legend()
plt.show()

2標本の比較

from scipy import stats
stats.ks_2samp(data1, data2)

データサイズは違っても構わない。

試してみる

①コーシー分布とコーシー分布
②コーシー分布とt分布(自由度3)
で比べてみる

y = stats.cauchy.rvs(size=500)
y1 = stats.cauchy.rvs(size=500)
z = stats.t.rvs(3, size=500)
print(stats.ks_2samp(y,y1).pvalue)
print(stats.ks_2samp(y,z).pvalue)
0.655550311167  # コーシー分布vsコーシー分布(>0.05)
0.022458470313  # コーシー分布vst分布(<0.05)

5%の基準だと、きちんと判別できている。


公式サイト:
scipy.stats.shapiro — SciPy v0.19.0 Reference Guide
scipy.stats.kstest — SciPy v0.14.0 Reference Guide
scipy.stats.ks_2samp — SciPy v0.15.1 Reference Guide