decision.py 解説
まず、analysis.pyを作動させるAMA.pyを見てみましょう。
AMD.py
import decision
# decisionを用いるという宣言
import pandas as pd
# pandasというpython内部の機構も使う
cards = ["BLK","AMP","BK","BX","IVZ","NTRS","STT","TROW"]
p = [356.58,96.38,39.71,25.30,27.60,67.11,57.46,74.08]
#cardsは用いる銘柄群で、pはそれぞれの現在の値
price = pd.read_csv("AMPrice.csv")
# analysisで作った値動きファイルを読み込み、投資判断に用います
data = decision.get_now(p,cards)
# get_nowという関数で[銘柄名、値段]となっているリストを作る
dev = decision.dev_n(data, price, cards)
# dev_nという関数でそれぞれの銘柄の現在の乖離率を計算
inv = decision.inv_n(dev,cards)
# inv_nという関数で乖離率よりそれぞれへの投資金額比率を計算
num_rate = decision.number_rate(data,inv,cards)
# 金額比率で出されても見辛いので株数比率に直します。これで何株うるのか、買うのかが出てきます。
print(num_rate)
# 出力
では、実際のdecision.pyを見ていきましょう。
import analysis
import numpy as np
import pandas as pd
import datetime
# いろいろ使うと宣言。このうちには前回銘柄分析に用いたanalysisも含まれます。
all_data = {}
def get_now(p,cards):
for i in range(len(p)):
all_data[cards[i]] = p[i]
return all_data
# これはp(価格リスト)とcards(銘柄リスト)を入力することでそれらを結びつける関数です。[銘柄1:価格1, 銘柄2:価格2,,,,,銘柄n:価格n]みたいなデータを出力します。
def dev_n(all_data, price, cards):
sigma = analysis.get_each_sigma(price, cards)
for i in cards:
all_data[i] /= sigma[i]
price[i] /= sigma[i]
norm = np.average(price[cards[0]])
for i in cards:
all_data[i] = all_data[i] - np.average(price[i]) + norm
print(all_data)
sum = 0
for i in cards:
sum += all_data[i]
sum /= len(all_data)
all_data["index"] = sum
dev={}
# ここまではanalysisでも行った標準化と、index(算術平均)の追加
for i in cards:
dev[i] = (all_data[i] - all_data["index"]) / all_data["index"]
# 乖離率を計算
dev["index"] = 0
return dev
def inv_n(dev,cards, norm = 0.04):
inv = {}
s = 0
l = 0
for i in cards:
if dev[i] >= norm:
s += dev[i]
elif dev[i] <= -norm:
l -= dev[i]
else: pass
# 若干複雑かもしれません。負の乖離率の合計値をlに、正の乖離率の合計をsに保存
# その際、normが障壁となります。乖離率の絶対値がnormより小さければ無視
for i in cards:
if dev[i] >= norm:
inv[i] = -dev[i]/s
elif dev[i] <= -norm:
inv[i] = -dev[i]/l
else: inv[i] = 0
return inv
# 乖離率絶対値がnormより大きいもののみを考える。乖離率が正に大きい程s(short値)が大きくなり、負に大きい程l(long値)投資比率が大きくなる
def number_rate(all_data,inv,cards):
num_rate = {}
min = 1
for i in cards:
num_rate[i] = inv[i]/all_data[i]
if num_rate[i] != 0 and abs(num_rate[i]) <= min:
min = abs(num_rate[i])
else: pass
for i in cards:
num_rate[i] = num_rate[i]/min *100
return num_rate
# 最後に金額比率をそれぞれの株価で割って株数比率に変える
analysis.py解説
まず、analysis.pyを作動させるAMA.pyを見てみましょう
僕自体が初心者なので、プログラミング初心者にわかるようには書けないかもしれません。流れだけでもわかって頂けたら幸いです。
import analysis
# analysis.pyを利用しますという宣言
cards = ["BLK","AMP","BK","BX","IVZ","NTRS","STT","TROW"]
# cardsは分析対象の銘柄を示しています。米国株はアルファベット複数文字で略されるので、これらのニックネームを用いてwebからデータを持って来れます。これらの相関係数や値動きの激しさを分析し、投資対象となるか、現状どうなのかを考えます
price = analysis.get_price(cards)
# analysis.py内のget_priceという関数(命令)を使ってcards内のそれぞれの要素の今までの値動きを持ってきます
price.to_csv("AMPrice.csv")
#そして、持ってきた値動きを"AMPrice.csv"というファイルに保存
analysis.normalize(price, cards)
# priceに入っている値動きに標準化(標準偏差による割り算及び、中心位置合わせ)
price = analysis.add_index(price,cards)
# price内部に全銘柄平均を追加します。これが乖離率計算のための基準となります
dev = analysis.dev_past(price, cards)
# 乖離率を計算させ、変数devを形成
dev.to_csv("AMDev.csv")
#乖離率の動きをcsvファイルに保存
analysis.show_graph(dev)
#最後に乖離率の遷移をグラフに移します。これはあってもなくても大丈夫です。
では、次にanalysis.pyを見ていきましょう。こちらは先のAMA.pyで使う関数をいろいろ詰め込んだ道具箱みたいになっています。
import matplotlib.pyplot as plt
import numpy as np
from pandas import Series,DataFrame
import pandas.io.data as web
import datetime
# いろいろimportしています。数学を用いる際や、グラフを出す際、webから情報を読み取る時などは裸のpythonに加えていろいろ道具を取り寄せる必要があります。これがimportです。
all_data={}
#株価を格納するための場所を作る(今は中身ゼロ)
def get_price(cards):
for ticker in cards:
all_data[ticker] = web.get_data_yahoo(ticker, (datetime.datetime.today() - datetime.timedelta(weeks = 208)), datetime.datetime.today())
# yahooからデータを取ってきています。今日を入れて208週間(4年間)分のデータを持ってきてそれぞれの銘柄、日にちに値する場所に入れています。
price = DataFrame({tic: data["Adj Close"]
for tic, data in all_data.items()})
#実際使うのは修正後終値(Adj Close)
return price
def get_each_sigma(price,cards):
#それぞれの値動きの標準偏差(動きの激しさ)を返す関数
sigma = [np.std(price[x]) for x in cards]
#標準偏差の計算
sigmadatas = Series(sigma, index=cards)
#標準偏差の値と銘柄名を1セットの情報にする
return sigmadatas
def normalize(price,cards):
# 標準化操作
sigma = get_each_sigma(price,cards)
# 先のget_each_sigma関数を呼び出して銘柄と標準偏差でセットの情報をもらう
for i in cards:
price[i] /= sigma[i]
norm = np.average(price[cards[0]])
# それぞれの標準偏差でそれぞれの値動きを割る
for i in cards[1:]:
price[i] = price[i] - np.average(price[i]) + norm
# Y軸中心を合わせる
def remove(price,cards,corrnorm=0.8):
# 基準(銘柄群の先頭にいる銘柄)との相関係数を計算し、相関係数が0.8以下の銘柄をcardsから削除する
corr0 = price.corrwith(price[cards[0]])
for i in cards[1:]:
if corr0[i] < corrnorm:
print(i + " is not appropriate.")
price = price.drop(i, axis=1)
# 仮に0.8より相関係数が低かった時、 "なんとか is not appropriate."と表示しprice内部からそのデータを省く
return price
# 不適合銘柄削除後の銘柄群とその値動きを返す
def add_index(price,cards):
# 銘柄群にそれらの平均値を加える
average = DataFrame({"index" : price.sum(axis = 1)/len(cards)})
return price.join(average)
def show_graph(price):
# グラフに映す操作
plt.figure()
price.plot()
plt.show()
def dev_past(price, cards):
# 乖離率の今までの遷移を返す関数
dev = price.copy()
# まず乖離率を格納する場所を作る
for i in cards:
dev[i] = (dev[i] - dev["index"])/dev["index"]
# 先に加えた平均値との差の絶対値を平均値で割り、乖離率を算出
dev["index"] = 0
return dev
AMAを作動させるとanalysisが呼び出されて結果、
"price.csv"、"dev.csv"ファイルとグラフが出てきます。
7/31 Pythonによる分析法(雑)
Pythonとは
数理系に強いプログラミング言語、AQRというクオンツファンドの人が能力の拡張を頑張ったおかげで金融系で結構使われているらしい。
僕が今月ちまちま勉強してできるようにしたのは、2つです。
一つはセクター別の株価分析。セクターの中である程度規模が大きい(株価の値動きの激しく無い)銘柄を決めたら(ここまでは手作業、株マップとかで)、株価の取得及びcsvファイルへの記録、値動きの激しさ(標準偏差)、それをもとにした標準化、相関係数計算、相関係数の低い銘柄の排除、それらを基にして現在までの乖離率の推移をグラフに映し出す為のプログラムです。このプログラムに入力として銘柄コードを与えてやればカタカタ働いて結果を返してくれます。
これにはanalysis.pyと名付けました(pyはPythonプログラムの事)
analysis.py
import matplotlib.pyplot as plt
import numpy as np
from pandas import Series,DataFrame
import pandas.io.data as web
import datetime
all_data={}
def get_price(cards):
for ticker in cards:
all_data[ticker] = web.get_data_yahoo(ticker, (datetime.datetime.today() - datetime.timedelta(weeks = 208)), datetime.datetime.today())
price = DataFrame({tic: data["Adj Close"]
for tic, data in all_data.items()})
return price
def get_each_sigma(price,cards):
sigma = [np.std(price[x]) for x in cards]
sigmadatas = Series(sigma, index=cards)
return sigmadatas
def normalize(price,cards):
sigma = get_each_sigma(price,cards)
for i in cards:
price[i] /= sigma[i]
norm = np.average(price[cards[0]])
for i in cards[1:]:
price[i] = price[i] - np.average(price[i]) + norm
def remove(price,cards,corrnorm=0.8):
corr0 = price.corrwith(price[cards[0]])
for i in cards[1:]:
if corr0[i] < corrnorm:
print(i + " is not appropriate.")
price = price.drop(i, axis=1)
cards = cards.remove(i)
return price
def add_index(price,cards):
average = DataFrame({"index" : price.sum(axis = 1)/len(cards)}) # should be improved
return price.join(average)
def show_graph(price):
plt.figure()
price.plot()
plt.show()
def dev_past(price, cards):
dev = price.copy()
for i in cards:
dev[i] = (dev[i] - dev["index"])/dev["index"]
dev["index"] = 0
return dev
もう一つは投資配分を出力するプログラム。入力としてanalysisの結果用いる事にした銘柄群、それとリアルタイムの株価(これを手に入れる方法はわかりませんでした)を入れる事で現在の乖離率を計算し、それぞれ買うべき、あるいは売るべき単位数を返してくれます。こちらはdecision.pyです。
import analysis
import numpy as np
import pandas as pd
import datetime
all_data = {}
def get_now(p,cards): #use new signals
for i in range(len(p)):
all_data[cards[i]] = p[i]
return all_data
def dev_n(all_data, price, cards): #use new price and cards
sigma = analysis.get_each_sigma(price, cards)
for i in cards:
all_data[i] /= sigma[i]
price[i] /= sigma[i]
norm = np.average(price[cards[0]])
for i in cards:
all_data[i] = all_data[i] - np.average(price[i]) + norm
print(all_data)
sum = 0
for i in cards:
sum += all_data[i]
sum /= len(all_data)
all_data["index"] = sum
dev={}
for i in cards:
dev[i] = (all_data[i] - all_data["index"]) / all_data["index"]
dev["index"] = 0
return dev
def inv_n(dev,cards, norm = 0.04):
inv = {}
s = 0
l = 0
for i in cards: #make s and l
if dev[i] >= norm:
s += dev[i]
elif dev[i] <= -norm:
l -= dev[i]
else: pass
for i in cards:
if dev[i] >= norm:
inv[i] = -dev[i]/s
elif dev[i] <= -norm:
inv[i] = -dev[i]/l
else: inv[i] = 0
return inv
def number_rate(all_data,inv,cards):
num_rate = {}
min = 1
for i in cards:
num_rate[i] = inv[i]/all_data[i]
if num_rate[i] != 0 and abs(num_rate[i]) <= min:
min = abs(num_rate[i])
else: pass
for i in cards:
num_rate[i] = num_rate[i]/min *100
return num_rate
あとはそれらのスイッチを入れるプログラムさえあればOKです。今回は米国株のアセットマネジメントセクターを用いてプログラムを書いたのでAMA(Asset Management Analysis)とAMD(Asset Management Decision)と名付けました。
AMA.py
import analysis
cards = ["BLK","AMP","BK","BX","IVZ","NTRS","STT","TROW"]
price = analysis.get_price(cards)
print(price)
price.to_csv("AMPrice.csv")
analysis.normalize(price, cards)
price = analysis.add_index(price,cards)
dev = analysis.dev_past(price, cards)
dev.to_csv("AMDev.csv")
analysis.show_graph(dev)
AMD.py
import decision
import pandas as pd
cards = ["BLK","AMP","BK","BX","IVZ","NTRS","STT","TROW"]
p = [356.58,96.38,39.71,25.30,27.60,67.11,57.46,74.08]
price = pd.read_csv("AMPrice.csv")
data = decision.get_now(p,cards)
print(data)
dev = decision.dev_n(data, price, cards)
print(dev)
inv = decision.inv_n(dev,cards)
num_rate = decision.number_rate(data,inv,cards)
print(num_rate)
コードだけ乗っけても不親切なので次から2回に分けてanalysisとdecisionを解説する会を作りますね。出来るかなー。
7/31 ロング・ショート戦略 反省4回目
今週は初の大損を出しました笑
トレダビで1000万円から始めたデモ口座の現状を確認します。
総資産額:10,037,109円 (- 125,225円)
評価損益:- 116,809円
先週は損してみたいとほざきましたが傷つきますなー。
サントリーに乖離率が一方的に離れる動きがあったのでそれで大損こいてしまいました。標準化された乖離率の一ヶ月間の動きがこちらです。
今週の間にサントリーが一方的にマイナス方向に伸びているのがわかります。僕のロングショートは乖離率が0 %へと収束する動きを予想しており、乖離率が大きくなるほど投資比率も大きくなるのでこの0から離れる動きで大損を出しています。12 %で損切りを考えているので、損切り間近であるとわかります。
まあこのグラフを見る限り一ヶ月の間に0に収束する動きがあるとは言えない事が判るので戦略の見直しが必要なのですがまずはサントリーの値動きが急にマイナスに偏った理由を考えましょう。
大きなニュースは流れてないので、ファンダメンタルには変化なし?
では、チャートはどうなっているでしょう。
直近の売買高に大きな変化はないのでやはりファンダメンタルズによるものではないでしょう。三ヶ月の日足チャートを見る限り、ダウントレンドの途中に休止期的なペナントが発生して、それの支持線が割れたのでダウントレンドが再開したって感じですかね。FX始めた頃はテクニカル信者で完全な信者だったんですけど、最近はあんまりで、これからも投資戦略に使う予定はありません。テクニカルって短期筋の動きだから長い目で見ればプラマイゼロになる気がするんだがどうなんだろう。
FXでは短期ポジションしかとった事ないのでわかりません。
今回わかったのは
①テクニカル的な動きでも大きな損失が出る事
→4銘柄ってやっぱ分散投資として足りてない事
②おそらく、トレンドが無い状態においてより高いパフォーマンスを発揮する事
→トレンドを感知するMACDとかスクリーニングに組み込んでやれば良くなりそう
→やっぱり銘柄増やさな
次回は今月中に勉強したPythonについて書きましょう。
戦略の方向としてはこのままで、銘柄を増やす単純作業になりそうです。
イノベーションが起きて構造が一気に変わり辛い食品銘柄を使うアプローチは正しいと思います。ただ、あまりにも分散性が低く、かつ今がどんな局面にあるか判断するスイッチが足りてい無いので今週のような損が生まれるのでしょう。
書く順番としては
pythonのおさらい → トレンド有る無しの判断機構構築 → 銘柄数増やしてテスト
という順番にする予定です。
7/24 今週のロング・ショート反省
反省3回目です。
トレダビで1000万円から始めたデモ口座の現状を確認します。
総資産額:10,162,334円 (+ 25,834円)
評価損益:26,016円
3週間連続でプラスでした。今週は3銘柄が乖離率をゆっくり低下させるいい動きをしていたのですが、サントリーが真逆の動きをしていたので相殺されて若干の増加という結果になりました。
この4銘柄の中でも味の素とキリン、サントリーと明治がそれぞれ非常に似通った動きをしており、もしかしたら4銘柄への投資より2つのペアトレードに分けたほうがいいのかもしれません。ただ、そうすると操作が増えるし、銘柄数が増加した時に無駄が増えるのでこのままの予定です。
ロング・ショートは「システムの安定」に賭ける手法です。だからこそ通常時は小さく儲け続け、システムの崩壊時には真っ先に壊滅します。小さく損したり、もしくはデモの内に崩壊を味わってみることができれば安心できるのですが。
今週は本業が忙しくて正直あまり考えられませんでした。毎日持分いじって、帰り道に軽く電車の中でpythonのコード少しづつ綺麗に(僕が思う綺麗に)していくだけでした。再来週あたりから頑張りたいです。
来週は月末なので一ヶ月の標準化された株価と乖離率の推移をお見せする予定です。あと、pythonのコードもできればお見せしたいです。今後はエクセルはやめてpythonで遊んで行く予定なので。
7/ 18 ロング・ショート反省、改良案
2週間経ったので反省2回目です。
先週やろうと決めた新セクターの導入とバックテストについては全く進んでません。代わりにPythonを勉強してます。株価の自動取得と、エクセルでやってたことをPythonにだいたい導入し終えました。がむしゃらにやってます笑。自分の中で整理できたら紹介したいです。
トレダビで1000万円から始めたデモ口座の現状を確認します。
総資産額:10,136,498円 (+122,293円)
評価損益:19,902円
一週間で1 %以上増えました。どこかおかしいですね。先週改良した低乖離率における利確も作動したので調子いいかもしれません。たまたまなのか、相場にあっているのか、それともどこか真をついた戦略なのかはまだ評価できないし、わかりません。もしかしたらBrexitにとって増加したボラティリティが収束する局面において斜に構えたロング・ショートがうまく働いてるのかもしれません。
そういえば、今週は任天堂が暴騰してました。ああいう動きはデイトレーダーにとっては面白いのでしょうが、僕の戦略からすれば恐怖でしかありません。相場全体から離れた個別的で明らかな一方的への動きはロング・ショートの天敵です。この観点から見れば、投資セクターを増やすのは分散によってシステムを強くする一方、ハズレくじを引かされる可能性を高めるデメリットもあります。投資するセクターはイノベーションが比較的起きづらい銘柄にするべきです。ITは避けて食品、小売、交通機関(これは寡占市場か)、金融なんかどうですかね。
投資は数字だけでやっていいものではありません。複雑な世界を単純に捉えて儲けるシステムはいずれ崩壊します。今回は対岸の火事(というか祭り)でしたが、このままでいれば僕のシステムも必ず壊滅的な打撃を受けるでしょう。だからこそ色んなことを学び、視界を広げ、それをシステムに導入していかねばなりません。そして壊滅的な打撃を、ギリギリ耐えられる深い傷くらいまでは軽減できれば、それがまた学びになります。
Pythonは面白いです。値動き分析も投資判断もできる無限のパズルです。前回勉強した時は目的なんかなかったので1ヶ月程楽しんだだけですぐ飽きましたが、今回はもうちょっと長く楽しめそうです。
ブラックスワン-あるいはロングショートへの罵詈雑言
タレブ氏の書いた「ブラックスワン(リスクと不確実性の本質)」を読んだ。衝撃だ。彼は僕のやろうとしている戦略を全否定している。アンチ・クオンツというか、アンチ・緩いクオンツだ。順を追って要旨をお伝えしたい。
ブラックスワンとは?
直訳すれば黒い白鳥。かつて全ての白鳥は白かった。オーストラリアに出向いた学者が黒い白鳥を見つけるまでは。よってタレブ氏はこれを「稀に起こる大惨事(祭)」、「予想できない危険な事象」の隠喩として用いている。
このブラックスワンにはタレブが言うには3つの特徴がある。
1.論理的には予測がつき辛い
2.与える影響が極めて大きい
3.過ぎ去ってしまうと、あたかも予測がつくものであったように見える
なるほど。面白い。リーマンショック、ソ連崩壊、ナチスの台頭、ナポレオンの敗北、ローマの興亡。後から振り返る僕らは全ての出来事に因果があるかの如く説明できる。そして、これらの因果を学ぶ事で将来なにかしらの予測が建てられると考えてる。あわよくばそれを利用して一儲けしようとも。タレブが言うには、これらは全部僕らの脳が効率よく情報を処理するために起きる錯覚らしい。ランダムな情報より意味のある、つながりのある情報の方が覚えやすい。つながりを元にひとまとめに置いておけるからだ。
だから僕らは出来事から無理に因果を作り出す。つながりが感じられる情報だけが強調されて脳に入ってくるのだ。
本当は非常に複雑で入り組んだ世界、システムを頭で無理やり作られた単純な因果で理解しようとする時、ブラックスワンが生まれる。(つながりを組み立てるのに)理想的な世界を作る過程で出来る先入観が目を曇らせて「予想外」を作るのだ。
ブラックスワンが生じるのはこの社会が「ベキ乗分布」でできているからだ。これは統計で使われる「正規分布」に比べて広い分布を持つ。このベキ乗分布は「計算しづらく」、「推測もしづらい」。要は複雑で、めんどくさいのだ。本当はめんどくさい世の中を計算しやすく、先も読みやすい正規分布を用いて理解して支配した気になっているから、いざベキ乗分布に見られる大きな動きが起きた時にパニックを起こし、思考が止まって損を出すんだ。
そういう訳でタレブは今までのクオンツを否定する。難しい世の中を簡単に解釈しようとすんじゃねーよ。頭の中で世界を勝手に決め付けて、それを前提に考えるから穴ができる。頭の中で出てきたリスクが全部だと思うなよ。正規分布なんざに頼ってちまちま儲けるのは目をつぶって幅のわからない橋を渡るみたいなもんだ。溜め込んだところでそれを突かれて、今までの賭け金が全て吹き飛ぶ。
そういう訳で、タレブは「バーベル戦略」を推薦する。賭けを2つに分けるのだ。一方は短期米国債に代表される「スーパー安全資産」、これはブラックスワンが来ようと吹き飛ばない、値上がりも値下がりも見込めない碇の役割を果たし、資産全体の85~90%を占める。もう一つは「スーパーハイリスク資産」、レバレッジかけてオプションでもなんでも利用してブラックスワン時に超巨大な儲けを出す機構を作るのだ。通常時は負けてていいのだ、どうせごく一部分だし。動きの大きさは果てしなく大きい、よって勝つ時の儲けも果てしなく大きくなる、らしい。
正直どうなん?色々無理あると思いますが。まず、ブラックスワンによる影響は予想できないので、短期米国債が安全であるとは言い切れないと思う。絶対に安全な資産なんて一つも存在しないはずだ、ベキ乗分布を考えるなら。第二に、予測できないブラックスワンで如何に儲けるのか?そんな事が出来るなら投資なんていうゲームとうに破綻しているはずだ。まあタレブは金融工学に精通しているのでクオンツの「穴」は見えやすいのかもしれない。第三に、タレブは3回しか儲けていないらしい。本の後書きで書いてる。クオンツショック、リーマンショックを含むいずれも金融市場に危機時だ。無論「大儲け」した回数だろうが、そんな少ない回数しか快感を感じられずに楽しいのだろうか。少なくとも、僕はいろんなタイミングで色んな波に乗って楽しみたいな。