ラベル システムトレード の投稿を表示しています。 すべての投稿を表示
ラベル システムトレード の投稿を表示しています。 すべての投稿を表示

2008/07/14

Black-Scholes Equation in Python 改良版

前回のコードをある程度改良しましたので、載せておきたいと思います。主な改良点は以下。

  • ヨーロピアン(コールorプット)オプションのデルタ、ガンマ、ベガ、シータ、ローを求める関数を追加しました。
  • ヨーロピアン(コールorプット)オプションのインプライド・ボラティリティをニュートン法より求める関数を追加しました。
  • その他若干の名称変更や、引数に関する説明を加えました。

数式は"Black-Scholes (1973) Option Pricing Formula"を参考にしました。

インプライド・ボラティリティに関しては適切な引数を加えないと、負の値や無限大に発散することがあるので注意が必要です。とはいえ実際の市場価格と理論価格がそこまで乖離することもないでしょうから、大抵正常な値を返すはずです。

商用、非商用に関わらず自由に使用、改変していいですし連絡する必要もないですが、無保証です。使う人はあんまいないと思いますが、一応建前として。

#!/usr/bin/env python
#-*- coding:utf-8 -*-
"""
Functions for calculating the Black-Scholes equation.
"""
import math

A1 = 0.319381530
A2 = -0.35653782
A3 = 1.781477937
A4 = -1.821255978
A5 = 1.330274429
RSQRT2PI = 0.3989422804
GAMMA = 0.2316419

def BS_Call(S,K,T,R,V):
"""Calculate the Black-Scholes formula for a call option.

Arguments:
S:the price of the underlying stock
K:the strike price
R:the continuously compounded risk free interest rate
T:the time in years until the expiration of the option
V:the volatility for the underlying stock
"""
d1,d2 = _getD1D2(S,K,T,R,V)
ret = S*_normalDist(d1)-K*math.exp(-R*T)*_normalDist(d2)
return ret

def BS_Put(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
ret = -S*_normalDist(-d1)+K*math.exp(-R*T)*_normalDist(-d2)
return ret

def BS_Call_IV(S,K,T,R,Pr,HV,maxNum=100,i=1):
"""Calculate the Implied Volatility using Newton's method.

Arguments:
Pr:the real price of call option
HV:the Historical Volatility
maxNum:the number of repeating calculation
i:index(Do not specify this parameter)
"""
if i > maxNum:
return HV
else:
newV = HV - (BS_Call(S,K,T,R,HV)-Pr)/BS_Vega(S,K,T,R,HV)
return BS_Call_IV(S,K,T,R,Pr,newV,maxNum,i+1)

def BS_Put_IV(S,K,T,R,Pr,HV,maxNum=10,i=1):
if i > maxNum:
return HV
else:
newV = HV - (BS_Put(S,K,T,R,HV)-Pr)/BS_Vega(S,K,T,R,HV)
return BS_Put_IV(S,K,T,R,Pr,newV,maxNum,i+1)

def BS_Call_Delta(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return _normalDist(d1)

def BS_Put_Delta(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return _normalDist(d1) - 1.0

def BS_Gamma(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return _normalDist(d1)/(S*V*math.sqrt(T))

def BS_Vega(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return S*_normalDist(d1)*math.sqrt(T)

def BS_Call_Theta(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return -S*_normalDist(d1)*V/(2*math.sqrt(T))-R*K*math.exp(-R*T)*_normalDist(d2)

def BS_Put_Theta(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return -S*_normalDist(d1)*V/(2*math.sqrt(T))+R*K*math.exp(-R*T)*_normalDist(-d2)

def BS_Call_Rho(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return K*T*math.exp(-R*T)*_normalDist(d2)

def BS_Put_Rho(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
return -K*T*math.exp(-R*T)*_normalDist(-d2)

def _getD1D2(S,K,T,R,V):
vSqrtT = V*math.sqrt(T)
d1 = (math.log(float(S)/K)+(R+(0.5*V*V))*T)/(vSqrtT)
d2 = d1 - vSqrtT
return (d1,d2)

def _normalDist(x):
if x >= 0:
k = 1.0/(1.0 + GAMMA*x)
cnd = RSQRT2PI*math.exp(-0.5*x*x)*(k *(A1+ k*(A2+ k*(A3 + k*(A4 + k*A5)))))
ret = 1.0 - cnd
return ret
else:
return 1.0 - _normalDist(-x)

て、そんなことやってる場合じゃない。早くテスト対策行なわないと。

2008/07/13

Black-Scholes Equation in Python


Photo by Martinlu, "Math"

やっぱ金融学んでるんだったら、オプションの理論価格ぐらい自分で出さないといけないよねー
ってわけで、あっちの方面では超がつくほど有名なBlack-Sholes Equotionをノリで実装してみました。特にこれといって特別なことはしてないですし、もう既にどっかの誰かがやってそうですが、こんくらい自分でやんないと。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import math

A1 = 0.319381530
A2 = -0.35653782
A3 = 1.781477937
A4 = -1.821255978
A5 = 1.330274429
RSQRT2PI = 0.3989422804
GAMMA = 0.2316419

def Black_Scholes_Call(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
ret = S*_normalDist(d1)-K*math.exp(-R*T)*_normalDist(d2)
return ret

def Black_Scholes_Put(S,K,T,R,V):
d1,d2 = _getD1D2(S,K,T,R,V)
ret = -S*_normalDist(-d1)+K*math.exp(-R*T)*_normalDist(-d2)
return ret

def _getD1D2(S,K,T,R,V):
vSqrtT = V*math.sqrt(T)
d1 = (math.log(float(S)/K)+(R+0.5*V*V)*T)/(vSqrtT)
d2 = d1 - vSqrtT
return (d1,d2)

def _normalDist(x):
if x >= 0:
k = 1.0/(1.0 + GAMMA*x)
cnd = RSQRT2PI*math.exp(-0.5*x*x)*(k *(A1+ k*(A2+ k*(A3 + k*(A4 + k*A5)))))
ret = 1.0 - cnd
return ret
else:
return 1.0 - _normalDist(-x)

ちなみに累積正規分布関数のところは5次の項まで近似した関数を使ってます。

2008/06/24

FXのレバレッジについて。


Photo by cobalt123, "Money, Hanging On"


レバレッジとは?

外国為替証拠金取引であるFXは、証券会社に証拠金を手渡すことによって、それを元手に何倍、何十倍もの通貨を取引することができ、その仕組みを「レバレッジ」と呼びます。

例えば1万円を証拠金として1ドル100円の通貨を1000個購入して、後に1ドル120円になったときに売却したとすると、購入したときの代金は100*1000 = 10万円。それが後に12万円になっているので、差益は12万円-10万円=2万円。レバレッジは10万円 / 1万円 = 10倍となります。要は金利のない借金みたいなものです。実際にかけられるレバレッジの量は証券会社によって違いがありますが、だいたい400倍くらいが最高のようです。

さて、他のFXについて言及しているブログではレバレッジについてあんまり詳しく書いていなくてちょっと不満だったので、これを数式にして、そのあとそれから生じるリスクについて考えてみることにしました。

レバレッジの数式

あなたは優秀な投資家で、常に安定した複利で資産を成長させることができるものします。それにレバレッジを常に一定の倍率でかけた場合、資産はどのように成長するのでしょうか?

まずN0を初めに投資する資産金額、rを1期間における複利、Lを1期間にかけるレバレッジの倍率と定義します。そうすると1期間後における資産金額N1は以下のように表せます。

これは第2項目までが1期間によって生じた収益、第3項が元の金額となっています。同様にこの数式を2期間後にも適応してみましょう。

このように綺麗な数式となりました。これを第n期間まで拡張すると、

となります。単純にレバレッジをかけずに運用した場合、L=1となるので、この式はrをL倍した複利で運用することに相当します。

で、結局なんなのさ?

具体例で考えてみることにします。もしあなたが年利10%で安定した運用を行えたとすると、これをレバレッジをかけずに10年間続けた場合の資産の倍率はL=1,r=0.10より
(1+0.1)^10 = 2.59
となります。それではレバレッジを仮に3倍でかけたとすると、L=3となるので、倍率は
(1+3*0.1)^10 = 13.79
となります。全然違いますね。Lの値がN0ではなく、指数関数に入っているところが恐ろしいです。

でもそんなおいしい話が転がっているわけがない

そりゃあ安定して10%も運用できればいいですが、普通は下落するリスクも併せ持っていることが普通です。14倍になるってことは資産が14倍下落するリスクも同様に併せ持っているということです。

仮にrが確率変数で、平均がµ,標準偏差がσだとすると、確率変数の性質よりLrの平均はLμ,標準偏差がLσとなってしまいます。このことよりリスクもリターンもLに比例していることがわかります。

しかもFXは一度でも資産があるデッドラインまで下がったら自動的にロスカットが実行されてしまいます。つまりレバレッジを上げるということは、資産を失う確率も高めるということです。

どれくらいのレバレッジなら許容できる?

追記。それではどれくらいのレバレッジならば、ロスカットとならずに比較的安定した運用ができるのでしょうか?

通貨をUSDJPYで固定して、1年間の運用を行うものと考えてみます。仮にrが正規分布に従う確率変数として、1年間のリターンをμ[%],1年間の標準偏差(ヒストリカルボラティリティ)をσ[%],ロスカットとなる利率を-d[%]とすると、限度であるレバレッジLは

となります。試しに計算してみましょう。スワップ派のサイトによると、USDJPYのHVはσ=6.95%であるので、今回は確実に安定して運用するために95%の確率で収束する2σを採用します。またμの値はUSDJPYのスワップポイントである、2.1%を採用します。そしてdを50%とすると、Lの値は
L = 50 / (6.95*2 - 2.1) = 4.24[倍]
となるので、レバレッジが4倍以内であれば、およそ95%の確率で安全圏に収束するということが分かります。

まとめ

  • 確実に利益を出せるという自信がない限り、あまりレバレッジを極端にかけないほうがよい。
  • 逆に言えば、確実に利益が出せる自信があるなら積極的にレバレッジをかけたほうがよい。
  • 何も考えずに400倍とかのレバレッジでやっている人はただのギャンブラー。

2008/05/29

ランダムフォレスト(Random Forest)法を用いて株価予測を行ってみた。-02

第二回。今回は予測を行うにあたって、統計ソフトであるRの"randomForest"パッケージを利用する方法を用いました。


randomForestパッケージのインストール


randomForestパッケージをRに追加するには、CRANからネットワークインストールを行うやり方が最もてっとり早いです。具体的にはRを起動させてから


> install.packages("randomForest")

と入力してください。コンパイルが開始されます。
もしコンパイラが存在しないとかでエラーがでた場合、apt-getかなんかで適当にインストールしてから、再度試みるとうまくいくはずです。


randomForestパッケージの利用


randomForestパッケージの利用手順は、おおまかに以下のようになります。

  1. library(randomForest)でパッケージを読み込む。
  2. dat.rf <- randomForest(formula ,data=dat ,ntree=500)
    でRFに学習させる。dataには学習に用いるデータテーブルを指定。formulaには推測に用いる変数を"y~x1+x2"のようにして記述する。y以外のすべての変数を推測に用いるならば"y~."とする。ntreeには発生させる決定木の数を指定する。
  3. dat.pred <- predict(dat.rf ,newdata=dat.test)
    でRFに推測させる。newdataには推測に用いるデータテーブルを指定する。
※補足
  • plot(dat.rf)とすると、決定木の数と予測精度の推移をグラフで見ることができる。
  • varImpPlot(dat.rf)とすると、各説明変数の予測に対する寄与度を見ることができる。
詳細は「randomForestパッケージのリファレンス(pdf)」を参照してください。
次回はこのパッケージを用いて実際に予測してみます。

2008/05/24

ランダムフォレスト(Random Forest)法を用いて株価予測を行ってみた。-01

randomForest

さて、今回は2001年ごろに登場した、比較的新しい手法と言われる集団学習の一派『ランダムフォレスト(Random Forest)』法を用いて株価の予測を行ってみました。

ランダムフォレストって?

ランダムフォレスト(RF; random forest)法は,集団学習法の一種である.集団学習(ensemble learning,アンサンブル学習とも呼ぶ)法は決して精度が高いとは言えない複数の結果を組み合わせ,精度を向上させる方法である.いわば,「三人寄れば文殊の知恵」である.集団学習法の中の代表的な方法としてはバギング法,ブースティング法,ランダムフォレスト法がある.
(p.256 金 明哲,村上 征勝『ランダムフォレスト法による文章の書き手の同定』,2007)

大体のイメージとしては、あんまり精度が良くない予測システムを200〜500個くらい作って組み合わせることで、精度の良い結果を得ようとする感じです。

他の手法に比べて利点は?

そもそも「データを元に何かを推測する」というやり方はとっても応用範囲が広い、しかも「推測」っていうのは人工知能と絡んでくるため、ずっとずっと前から研究が続けられてきて、様々な手法が開発されてきました(e.g. Artificial Neural Network(ANN),Genetic Algorism(GA),Support Vector Machine(SVM),...and more!!)。その中の1つとして集団学習があり、さらにその中の1つとしてランダムフォレストがある感じです。

それじゃあランダムフォレストは他の手法と比べて何か利点はあるの?というと、以下の通りとなります。

  • 多くのデータセットを用いることによって、とても正確な分類を行うことができる。
  • 非常に多くの説明変数を扱うことができる。
  • データマイニングにおける分類問題において、説明変数の重要度を見積もることができる。
    (結構重要。他の手法は主にどの変数によってアウトプットが決定されるのか分からないものがある。)
  • 欠損したデータを良い精度で推測できるので、データの大部分が欠損していても正確さを保つことができる。
  • 従来の手法に比べて、学習速度が早い。

などなど…(英語版のwikipediaよりいくつかの項目を超訳しました)
ランダムフォレストについて詳しく知りたい方は、『Breiman, Leo (2001). "Random Forests". Machine Learning (pdf)』を参照してください。

とりあえず長くなりそうなので今日は概要まで。次回から具体的な手法に入っていきます。

2008/03/21

システムトレードの研究-2

第一回の続きです。今回は初めてのプログラムと言うことなので、平均-分散(mean-variance)理論を利用して簡単なプログラムを組んでみます。

プログラムに用いる言語は何が最適?

  1. MetaTraderなどの独自言語
    単純なプログラムの場合はこれが一番効率的だが、いちいち覚えなきゃいけないのがめんどくさい。あと今回扱うデータは30万×6通貨と大量なんで、速度や安定性も心配。
  2. C or C++
    速度から見れば一番最適なんだけど、コードの行数が単純に多くなる。ポインタ関係のバグとかで手間取るのは勘弁。
  3. Rとかの統計言語
    データ解析で非常に活躍するが、バックテストを行うのには不向き?(本来の分野とはかけ離れている)
  4. C# , VB.net などの .net 言語
    一番最適なような気がする。システム部分をいちいち製作しなきゃいけないけれど、その分柔軟性があり、なによりC# 3.0からLinqとラムダ式という超強力な武器が手に入る。速度の問題も気になるところはunsafe or 外部dllという手段があるし。
  5. Haskell or Ocaml
    関数型言語で実装したほうがコード数が少なくなる場合が多々あるし、なにしろこのタイプの言語は数学系統に強い。現在は見送るが、将来的に学びたい言語。

といろいろ検討した結果、C#となりました。

始めに作ったプログラム

始めに作った売買プログラムは非常に簡単で、以下の手順だけでシステムを組みました。

なお今回取引する金融商品はFX,売買する通貨はオーストラリアドル、スイスフラン、ユーロ、英ポンド、ニュージーランドドル、アメリカドル / 円の6つで、実際の取引に生じるスプレッド、スワップポイントは今回無視しました。

  1. 過去10分前までのデータから収益率r、その標準偏差σを計算し、評価関数

    を用いてランク付けする。
  2. 一番上のランクになった通貨を売買。期待収益率が正ならば対象通貨を買い、負ならば対象通貨を売る。
  3. その10分後に対象銘柄を売却か、購入する。

これを1年間に渡って繰り返した場合、100万円の元出がいくらかになったかを計算します。評価に用いた為替レートの1分足データはForexiteから取得しました。

で、作ったプログラムが以下。正直適当です。


問題発生

ところがこのようなシステムを実際に稼動してみると、どうも収益が逆に-20,30万くらい少なくなっている傾向があるようです。これでは良いシステムとは言えません。

そこでそれなら逆転の発想で、単純に売買ルールを逆にしてみればプラスになるんじゃ!ということでシステムを稼動してみると、思惑通りプラスとなりました。今回のバックテストで得られた結果のグラフがこちらです。

カーブの大小はありますが、どれも上方向を向いており、マイナスの結果になっているグラフはありません(ただし月単位で見た場合、負の収益を出している月もある点に注意)。また収益もスプレッドを無視しているとはいえ、含み益が150万~380万。年利換算で150% ~ 380%。平均の月利は約8.0~11.8%という結果になりました。これは明らかに今回の取引が「劣マルチンゲール(有利な取引)」であることを表しています。

なぜそんなことが起こるのか

もし微小時間の値動きがブラウン運動のような完全にランダムな値動きをするならば、このように4年連続で、しかも比較的綺麗な損益曲線を描くことにはならないはずです。このことから以下のように結論付けることにしました。

少なくとも過去4年間、外国為替市場における為替のレートは微小時間で正または負の方向に値が進んでいる場合、後にその動きとは逆の値動きになる傾向がある。


なぜこのような値動きになるのか。これはあくまで仮定ですが、自分は以下のように考えました。

  • 外国為替市場では売りの圧力と買いの圧力がせめぎあって、その理想均衡点が価値を決定する。
  • その理想均衡点の動きは緩やかに推移していくため、微小時間では無視することができる。
  • もし価値が理想均衡点から明らかに乖離した値をとる場合、市場は価値が理想均衡点となるように逆方向の圧力がかかり、補正される。

これならば上の結論の説明がつきそうです。そして2007年の収益が最も少なかった理由として、

「2007年はサブプライム問題などにより売り買いの圧力が大きく変動したため、理想均衡点自体が大幅に変動し、予測がしにくかったのではないか」

と推論しました。

次回はこの仮定を検証してみますが、それよりもまずは金融工学をもっと勉強しなきゃ・・・(まだ300ページしか読み終わってない)自分が知らないことはまだまだたくさんある。

追記(03/23)

年利換算が間違っていたので修正しました。資産額じゃなくて純利益だったのを忘れてました。だめだこりゃ。

2008/03/20

システムトレードの研究-1

金融工学を学んでいる途中なんですけど、ぼちぼち平行してシステムトレードの研究をしてみたいと思います。映像とは全く関係ないっすねぇ :) もうそろそろブログのタイトルを違うものにしたほうがいいかもしれないです。

というわけでシステムトレードの研究です。この記事は正直研究日誌的なもので、実際に運用している人にとっては全く役立たないっす。数ヵ月後自分がこの記事を見て「うわぁこれはねーよ」って言って赤面するために書いてます。あんま気にしないでください。

うっし。それじゃあ書いていくか。

システムトレードとは

投資法の一種で、一般にはプログラミングによって金融商品の分析、売買を全てコンピュータに委託させる手法のことを指している。広義では一定のルールを予め決め、そのルールに従って売買を繰り返す手法もシステムトレードと言うので、必ずしもコンピュータで完全に自動売買させることを指すわけではない。

システムトレードの利点

  • 過去のデータを用いてシステムの検証ができる。過去のあらゆる時点でテストを行うことによって、その構築したシステムのパフォーマンスや欠点が判明し、よりよいシステムを構築することができる。
  • 感情を廃して取引を行えるため、きちんとしたプログラムを組めば人間よりも合理的な判断を行える。
    ex.人間は「損を極端に嫌う」という傾向がある。そのため一旦損をしてしまうと、その補填をしようと何回もリスクのある取引を行ってしまい、深みにはまってしまう(ざわ・・・ざわ・・・)とか。

システムトレードの欠点

  • 過去に無い相場に遭遇した場合、損失を出すリスクが高くなる。
  • 過度にパラメータを最適化してしまうと、未知の事象に対処しきれなくなってしまうため、むしろ損失してしまう場合がある。

欠点を克服するにはどうすればいい?

  • 十分に長い期間(5年以上くらい)バックテストを行うことで、システムのパフォーマンスや欠点を分析する。
  • パラメータが現時点において適切であるような「合理的」なパラメータになるよう学習させる。

雑感

  • システムトレードで検索すると胡散臭いサイトばっかり出てくるのはなんで?プログラムで自分は何もしなくて良いという所が受けるんだろうか。
  • システムトレードでExcelを使っている人が多いけど、個人的にはそんなにExcel VBA使いたがるのか理解できない。
  • という自分はC#信者。
  • なんで金融系ってオープンソースコミュニティが成熟していないんだろう。あんまそういう閉鎖的な部分ってよくないと思うんすけどねぇ

次に実際に自分がプログラムしたシステムトレードについて書いていきます。