LoginSignup
2
2

More than 5 years have passed since last update.

Most Simple Algorithm Trade - パフォーマンス良好か?

Last updated at Posted at 2015-06-15

"Python for Finance" (by Yves Hilpisch, O'reilly media) は全体が3部構成になっていて,Part-1は導入的な内容が書かれている.そのPart-1でPythonツールでできることの例として,米国株式インデックスS&P500の移動平均を用いた簡単なAlogorithm Tradeの説明があり,目が留まった.case studyの最終利益率が2.5倍を越えていて何ともポジティブな印象を持った反面,本当に話が合っているのか確認してみたくなった.

まず,本文通りにプログラムを実行し,さらに追加でパラメトリックなスタディをしてみる.

S&P500は,いわばアメリカ版Nikkei 225のようなもの.2000年以降,ネットバブルの影響と,リーマンショックの影響により,下図のようなチャートとなる.

図.The S&P 500 index with 42d 252d trend lines
TL_42d-252d.png

(緑色の42d lineが見にくいです...)

ここで2つの移動平均線(42day, 252day)に着目し,その動きから以下のTrade Action ルールを定める.

  • Buy signal (go long) - the 42d trend is SD points above the 252d trend
  • Wait (park in cash) - the 42d trend is within a range of +/-SD points around the 252 trend
  • Sell signal (go short) - the 42d trend is SD points below the 252d trend

SDは,(何の略であるか説明は無かったが)trade signalに対する一種のしきい値とのことである.ルールは以上で,これをpython codeにして計算する.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# import pandas.io.data as web
#
# sp500 = web.DataReader('^GSPC', data_source='yahoo', start='1/1/2000', end='4/14/2014')

sp500 = pd.read_csv('./sp500.csv', index_col='Date', parse_dates=True)

mid_term = 42                        # parameter-A : moving average length (Mid.term)
long_term = 252                      # parameter-B : moving average length (Long term)
mid_label = str(mid_term) + 'd'
long_label = str(long_term) + 'd'
sp500[mid_label] = np.round(pd.rolling_mean(sp500['Close'], window=mid_term), 2)
sp500[long_label] = np.round(pd.rolling_mean(sp500['Close'], window=long_term), 2)

sp500[['Close', mid_label, long_label]].plot(grid=True, figsize=(8, 5))
sp500['mid-long'] = sp500[mid_label] - sp500[long_label]

SD = 50                             # parameter-C : threshold of trade action
# 
sp500['Regime'] = np.where(sp500['mid-long'] > SD, 1, 0)
sp500['Regime'] = np.where(sp500['mid-long'] < -SD, -1, sp500['Regime'])
sp500['Regime'].value_counts()
#
plt.figure()
sp500['Regime'].plot(lw=1.5, figsize=(8,2))
plt.ylim([-1.1, 1.1])

sp500['Market'] = np.log(sp500['Close'] / sp500['Close'].shift(1))
sp500['TradeReturn'] = sp500['Regime'].shift(1) * sp500['Market']
sp500[['Market', 'TradeReturn']].cumsum().apply(np.exp).plot(grid=True, figsize=(8,5))

上のリストはほぼ文献からの引用だが,一部,変更している.
- パラメトリック・スタディのため,移動平均の平均化区間を変更しやすくしている.
- SD も(変数の定義だけだが)パラメータとして明示的に変更するようにした.
- S&P500は,’yahoo.com'からデータを入手する,というのがオリジナル.(今回は,最初にwebサイトから取ってDisk保存し,それを繰り返し読むようにした.)

pandasで簡潔に書かれているが,

sp500[mid_label] = np.round(pd.rolling_mean(sp500['Close'], window=mid_term), 2)

ここでは,移動平均計算の *pd.rolling_mean() * を用いている.

sp500['Market'] = np.log(sp500['Close'] / sp500['Close'].shift(1))
sp500['TradeReturn'] = sp500['Regime'].shift(1) * sp500['Market']
sp500[['Market', 'TradeReturn']].cumsum().apply(np.exp).plot(grid=True, figsize=(8,5))

ここでは,DataFrame オブジェクトに cumsum(), apply(np.exp) した後(累積値を求めてLogを元に戻して)plot()している.ここら辺の関数の使い方はとても参考になる.

結果は下図の通り.

** Fig. Signal regimes over time **(-1 : Shortの合図,+1:Longの合図)

TSig_42d-252d.png

** The S&P 500 index vs. investor's wealth **

Return_42d-252d.png

S&P 500 index自体が増加率 1.3 (130%) であるのに対し,投資行動の結果の利益率が 2.7 (270%) となっている.この結果について著者は以下を述べている.

  • 実際のTradeでは売買手数料が発生するので,利益率は落ちる結果となるだろう.
  • 株価上昇trend時より,下落trendの状況下で(Short Positionを作ることで)大きく利益を挙げている.

2度の経済的危機(ネットバブル崩壊,リーマンショック)を経過した中で資産2.7倍はかなり魅力的に見える.(シンプル極まりないAlgorithm Tradeにしては良好である.)もしかすると移動平均の使い方や,Trade Signalのしきい値の設定が偶然よかったからなのでは? という疑問がわいた.以下,調べてみた.

移動平均区間(averaging period)を変更してみる

文献記載の移動平均計算区間は (Mid, Long) = (42day, 252day) であった.これを以下のように変えて計算した.

(Mid, Long) = (42day, 126day)

TSig_42d-126d.png
Return_42d-126d.png

カーブの類似性が上がったため,Trade Signalの発生の頻度が下がった模様.

(Mid, Long) = (84day, 126day)

TSig_84d-126d.png
Return_84d-126d.png

さらにTrade Signalの発生しなくなった.(ほとんど何もしていない状態.)

(Mid, Long) = (84day, 252day)
TSig_84d-252d.png
Return_84d-252d.png

状況は最初のもの(42day, 252day)に近づいた.但し,最終利益率は約2.2 (220%)で最初の数字(約2.7)より劣っている.

Trade Signalのしきい値を変更してみる

文献記載のTrade Signalしきい値 SD = 50 であった.これは,S&P 500 のindexに対する値であることに注意が必要である.(S&P 500 = 1000 の時に 5%の差分をみていることになる.)

SD = 20

TSig_SD=20.png
Return_SD=20.png

Signal Profileが -1.0 や +1.0 にへばりついているのは,休みなく売買していることを示している.最終利益率は,最初の値より若干upした.(約 2.8~2.9)

SD = 100

TSig_SD=100.png
Return_SD=100.png

Trade頻度は,かなり低下してる.結果は最悪で.なんと index にすら負けている.

以上のような結果でした.

  • 予想した通り,文献記載のパラメータは(経験的に選択したのかも知れないが)相対的に「うまい」設定のように見える.
  • 唯一,SD=20 (しきい値を下げた)条件で,若干パフォーマンスが改善した.(もちろんTrade手数料は無視するという前提はそのまま.)
  • この2つの移動平均線を参考にする方法は,「ゴールデンクロス」「デッドクロス」と世の中で呼ばれているもので一般的らしい.

最初,利益率2.6倍にひかれましたが,よくよく考えると14年間でこれですから年率にすると8%前後の数字になってしまいます.実際の投資としては,それほど魅力ある内容ではない(?)のかも知れません.(但し,個人的に pandasの勉強にはなりました.)

参考文献
- "Python for Finance": (O'reilly Media) http://shop.oreilly.com/product/0636920032441.do
- pandas 公式ドキュメント http://pandas.pydata.org/pandas-docs/stable/index.html

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2