在 Python 中为 3 个 ETFEWA、EWC、IGE实现协整投资组合

问题描述

我正在尝试使用 P.E. 博士在“算法交易”中描述的策略来实施均值回归投资组合。陈。但是,由于他使用的示例是在 MATLAB 中编写的,因此我无法将它们正确转换为 Python。我完全无法使用 3 个 ETF 创建一个协整投资组合。我认为我的问题始于尝试确定对冲,然后构建所需的投资组合。

任何帮助或提示都会非常有用。

因此,我首先下载调整后的价格并创建 W、X 和 Y 数据系列。我选择的时间段是 2007/07/22 到 2012/3/28。

import numpy as np
import pandas as pd
import pandas_datareader.data as web
import matplotlib.pyplot as plt
%matplotlib inline

import statsmodels.api as sm

import datetime

start = datetime.datetime(2007,7,22)
end = datetime.datetime(2012,3,28)
EWA = web.DataReader('EWA','yahoo',start,end)
EWC = web.DataReader('EWC',end)
IGE = web.DataReader('IGE',end)

w = IGE['Adj Close']
x = EWA['Adj Close']
y = EWC['Adj Close']

df = pd.DataFrame([w,x,y]).transpose()
df.columns = ['W','X','Y']
df.plot(figsize=(20,12))

from statsmodels.tsa.vector_ar.vecm import coint_johansen

y3 = df

j_results = coint_johansen(y3,1)

print(j_results.lr1)                           
print(j_results.cvt)                           
print(j_results.eig)
print(j_results.evec)
print(j_results.evec[:,0])

那么我应该通过将特征向量 [0.30..,1.36..,-1.35..] 乘以每种工具的股价来构建一个投资组合,以获得 y_port 值。之后,我进行了相关性测试,以确定该投资组合的每日价格变化与最后一天价格变化之间的相关性,从而能够确定该系列的半衰期。

我只是将特征向量乘以收盘价来做到这一点,我不知道这是否是我出错的地方。

    hedge_ratios = j_results.evec[:,0]
    y_port = (hedge_ratios * df).sum(axis=1)
    y_port.plot(figsize=(20,12))

    y_port_lag = y_port.shift(1)
    y_port_lag[0]= 0
    delta_y = y_port-y_port_lag

    X = y_port_lag
    Y = delta_y
    X = sm.add_constant(X)

    model = OLS(Y,X)
    regression_results  = model.fit()
    regression_results.summary()

那么我计算了半衰期,大约是 19 天。

halflife = -np.log(2)/regression_results.params[0]
halflife

我根据书上的说明定义了要持有的单位数量(投资组合价值的 -Z 值,基于半衰期的回溯期为 19 天)。

num_units = -(y_port-y_port.rolling(19).mean())/y_port.rolling(19).std()
num_units.plot(figsize=(20,12))

所以我接下来要采取的步骤是:

  1. 检查数据框是否仍然正确。

  2. 添加“要持有的单位数”,这是之前计算的,是 y_port 值的负 Z 分数。

  3. 可能有更简单的方法来乘以或执行此操作,但我通过将工具价格乘以特征向量给出的对冲比率,再乘以要持有的投资组合单位。

  4. 最后,我通过乘以每日变化 * 我持有的单位数量来计算每个工具的盈亏。

结果很糟糕。就是从头到尾都输了。 ¿我在哪里搞砸了? ¿如何正确地乘以特征向量中的值,确定要持有的头寸数量,并正确创建投资组合?

任何帮助将不胜感激。

  1. 我不知道为什么,但是 num_units 系列是“水平的”,我必须在将它附加到 DataFrame 之前对其进行转置。
num_units = num_units.transpose()
df['Portfolio Units'] = num_units
df
df['W $ Units'] = df['W']*hedge_ratios[0]*df['Portfolio Units']
df['X $ Units'] = df['X']*hedge_ratios[1]*df['Portfolio Units']
df['Y $ Units'] = df['Y']*hedge_ratios[2]*df['Portfolio Units']

positions = df[['W $ Units','X $ Units','Y $ Units']]
positions

pnl = pd.DataFrame()

pnl['W Pnl'] = (df['W']/df['W'].shift(1)-1)*df['W $ Units']
pnl['X Pnl'] = (df['X']/df['X'].shift(1)-1)*df['X $ Units']
pnl['Y Pnl'] = (df['Y']/df['Y'].shift(1)-1)*df['Y $ Units']
pnl['Total PNL'] = pnl.sum(axis=1)

pnl['Total PNL'].cumsum().plot(figsize=(20,12))

我知道如果我只是恢复我的位置(不在 y_port 中使用 -1),结果会改变,我会得到正回报。但是,我想知道我做错了什么。将 -Z 用于均值回归策略是有道理的,我想知道我在哪里犯了错误,以便我可以跟上本书的其余部分,

解决方法

我认为您还需要将 df['W $ Units']、df['X $ Units'] 和 df['Y $ Units'] 移至 1。例如,要使用 df['Y $ Units'].shift(1) 而不是 df['Y $ Units']。

您收到的结果并不糟糕 - 这是不现实的。在不移动 df['... $ Units'] 的情况下,您正在展望未来并使用尚不可用的数据。