先物取引におけるロールオーバーの累積リターンをモデル化してみる

## 先物取引のモデル化

基本的に[前々回](http://qiita.com/ynakayama/items/32b1ca2a108876f889cc)と[前回](http://qiita.com/ynakayama/items/1801d374224d6914a382)の続きです。

今日は[先物取引](http://ja.wikipedia.org/wiki/%E5%85%88%E7%89%A9%E5%8F%96%E5%BC%95)の中でも定番の「[金](http://www.comtex.co.jp/www/?module=Default&action=meigara&page=sheet1&article=T-kin)」について実際にロールオーバーから連続的なリターンを構築、予測やモデル化の一助に利用してみようという話です。

[ロールオーバー](http://www.ifinance.ne.jp/glossary/derivatives/der087.html)とは簡単に言うと先物取引の期限が迫る契約からすぐ先もしくはだいぶ先の契約へと移行することです。取引残高の継続的な推移をモデル化するには市場や取引の様々な条件を加味しなければなりませんが、ここでは線形に推移するシンプルなモデルを考えてみます。

### 銘柄の選択

[Gold Futures Rollover Dates 2013](http://stockguy22.com/gold-futures-rollover-dates-2013/) を参照して適当な銘柄を選びます。執筆時点では 3/13 ですので直近で契約期限日 (Last Trade) を迎える GCJ14 と GCM14 に狙いを定めてみましょう。

### ランダムウォーク

[ランダムウォーク](http://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%83%BB%E3%82%A6%E3%82%A9%E3%83%BC%E3%82%AF%E7%90%86%E8%AB%96)で先物取引の契約をシミュレートします。

```py3
def random_walk(px, n, f):
    np.random.seed(34567)
    N = 200
    _walk = (np.random.randint(0, 200, size=N) - 100) * 0.25
    perturb = (np.random.randint(0, 20, size=N) - 10) * 0.25
    walk = _walk.cumsum()
    rng = pd.date_range(px.index[0], periods=len(px) + N, freq='B')
    near = np.concatenate([px.values, px.values[-1] + walk])
    far = np.concatenate([px.values, px.values[-1] + walk + perturb])
    prices = pd.DataFrame({n: near, f: far}, index=rng)
    return prices
```

ランダムウォークの関数ができました。
ではこれに Yahoo! ファイナンスのデータを渡してみましょう。

```py3
# SPY 投資信託の基準価格を S&P 500 インデックスのおよその価格として利用
px = web.get_data_yahoo('SPY')['Adj Close'] * 10
# 銘柄と契約期限日を指定
expiries = {
    'GCJ14': datetime(2014,4,28),
    'GCM14': datetime(2014,6,26)
}
expiry = pd.Series(expiries).order()

print( px.tail(5) )
# => 
# Date
# 2014-03-06    1881.8
# 2014-03-07    1882.6
# 2014-03-10    1881.6
# 2014-03-11    1872.3
# 2014-03-12    1872.8

print( expiry )
# =>
# GCJ14   2014-04-28
# GCM14   2014-06-26

prices = random_walk(px, 'GCJ14', 'GCM14')
print( prices.tail(5) )
# =>
#               GCJ14    GCM14
# 2014-10-17  1618.80  1621.05
# 2014-10-20  1634.80  1632.55
# 2014-10-21  1622.55  1623.80
# 2014-10-22  1638.55  1639.30
# 2014-10-23  1637.55  1638.30
```

### 重み付け

次に重み付けを計算するモデルを構築します。コードはオライリー本そのままです。

```py3
def get_roll_weights(start, expiry, items, roll_periods=5):
    dates = pd.date_range(start, expiry[-1], freq='B')
    weights = pd.DataFrame(np.zeros((len(dates), len(items))),
                        index=dates, columns=items)
    prev_date = weights.index[0]
    for i, (item, ex_date) in enumerate( expiry.iteritems() ):
        if i < len(expiry) - 1:
            weights.ix[prev_date:ex_date - pd.offsets.BDay(), item] = 1
            roll_rng = pd.date_range(end=ex_date - pd.offsets.BDay(),
                                     periods=roll_periods + 1, freq='B')
            decay_weights = np.linspace(0, 1, roll_periods + 1)
            weights.ix[roll_rng, item] = 1 - decay_weights
            weights.ix[roll_rng, expiry.index[i + 1]] = decay_weights
        else:
            weights.ix[prev_date:, item] = 1
        prev_date = ex_date
    return weights
```

### 連続的なリターンの算出

最後にこれらの関数を利用して連続的なリターンインデックスを求めます。

```py3
weights = get_roll_weights('3/11/2014', expiry, prices.columns)

sample_prices  = prices.ix['2014-04-17' : '2014-04-28']
sample_weights = weights.ix['2014-04-17' : '2014-04-28']
sample = sample_prices * sample_weights

# データフレームを新しく構築
result = pd.DataFrame({'GCJ14': sample['GCJ14'], 'GCM14': sample['GCM14'], 'GOLD': sample['GCJ14'] + sample['GCM14'] })

# ロールオーバーされた先物取引のリターンを得る
print( result )
# =>
#               GCJ14    GCM14     GOLD
# 2014-04-17  1663.30     0.00  1663.30
# 2014-04-18  1687.55     0.00  1687.55
# 2014-04-21  1348.24   337.16  1685.40
# 2014-04-22  1017.78   678.42  1696.20
# 2014-04-23   676.62  1015.53  1692.15
# 2014-04-24   338.01  1351.84  1689.85
# 2014-04-25     0.00  1705.55  1705.55
# 2014-04-28     0.00  1723.05  1723.05
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/38501/74eb5d75-3f3c-f481-5d54-724a2a9f6272.png)

株式ポートフォリオを分析するのはこれくらいにして次回以降はまた別の分野に応用していきます。

## 参考

Pythonによるデータ分析入門――NumPy、pandasを使ったデータ処理
http://www.oreilly.co.jp/books/9784873116556/