Profesor, MAF ITESO
En primer lugar, para poder bajar precios y información sobre opciones de Yahoo, es necesario cargar algunos paquetes de Python. En este caso, el paquete principal será Pandas. También, se usarán el Scipy y el Numpy para las matemáticas necesarias y, el Matplotlib y el Seaborn para hacer gráficos de las series de datos.
In [1]:
#importar los paquetes que se van a usar
import pandas as pd
import pandas_datareader.data as web
import numpy as np
import datetime
from datetime import datetime
import scipy.stats as stats
import scipy as sp
import scipy.optimize as scopt
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn.covariance as skcov
%matplotlib inline
#algunas opciones para Python
pd.set_option('display.notebook_repr_html', True)
pd.set_option('display.max_columns', 6)
pd.set_option('display.max_rows', 10)
pd.set_option('display.width', 78)
pd.set_option('precision', 3)
Bajar datos en forma de función
In [2]:
def get_historical_closes(ticker, start_date, end_date):
p = web.DataReader(ticker, "yahoo", start_date, end_date).sort_index('major_axis')
d = p.to_frame()['Adj Close'].reset_index()
d.rename(columns={'minor': 'Ticker', 'Adj Close': 'Close'}, inplace=True)
pivoted = d.pivot(index='Date', columns='Ticker')
pivoted.columns = pivoted.columns.droplevel(0)
return pivoted
Una vez cargados los paquetes, es necesario definir los tickers de las acciones que se usarán, la fuente de descarga (Yahoo en este caso, pero también se puede desde Google) y las fechas de interés. Con esto, la función DataReader del paquete pandas_datareader bajará los precios solicitados.
Nota: Usualmente, las distribuciones de Python no cuentan, por defecto, con el paquete pandas_datareader. Por lo que será necesario instalarlo aparte. El siguiente comando instala el paquete en Anaconda: conda install -c conda-forge pandas-datareader
In [6]:
assets = ['AAPL','MSFT','AA','AMZN','KO','QAI']
closes=get_historical_closes(assets, '2016-01-01', '2017-09-22')
closes
Out[6]:
In [7]:
closes.plot(figsize=(8,6));
Nota: Para descargar datos de la bolsa mexicana de valores (BMV), el ticker debe tener la extensión MX. Por ejemplo: MEXCHEM.MX, LABB.MX, GFINBURO.MX y GFNORTEO.MX.
In [8]:
def calc_daily_returns(closes):
return np.log(closes/closes.shift(1))[1:]
In [9]:
daily_returns=calc_daily_returns(closes)
daily_returns
Out[9]:
In [10]:
daily_returns_b=calc_daily_returns(closes)
yb=0.000001
daily_returns_b['BOND']=yb*np.ones(daily_returns.index.size)
daily_returns_b
Out[10]:
In [11]:
mean_daily_returns = pd.DataFrame(daily_returns.mean(),columns=['Mean'],index=daily_returns.columns)
mean_daily_returns
Out[11]:
In [12]:
mean_daily_returns_b = pd.DataFrame(daily_returns_b.mean(),columns=['Mean'],index=daily_returns_b.columns)
mean_daily_returns_b
Out[12]:
In [13]:
cov_matrix = daily_returns.cov()
cov_matrix
Out[13]:
In [14]:
daily_returns.corr().stack().sort_values(axis=0, ascending=True, kind='quicksort')
Out[14]:
In [15]:
cov_matrix_b = daily_returns_b.cov()
cov_matrix_b
Out[15]:
In [16]:
#robust_cov_matrix= pd.DataFrame(skcov.EmpiricalCovariance().fit(daily_returns).covariance_,columns=daily_returns.columns,index=daily_returns.columns)
#robust_cov_matrix= pd.DataFrame(skcov.EllipticEnvelope().fit(daily_returns).covariance_,columns=daily_returns.columns,index=daily_returns.columns)
#robust_cov_matrix= pd.DataFrame(skcov.MinCovDet().fit(daily_returns).covariance_,columns=daily_returns.columns,index=daily_returns.columns)
robust_cov_matrix= pd.DataFrame(skcov.ShrunkCovariance().fit(daily_returns).covariance_,columns=daily_returns.columns,index=daily_returns.columns)
robust_cov_matrix
Out[16]:
In [17]:
robust_cov_matrix_b= pd.DataFrame(np.insert((np.insert(skcov.ShrunkCovariance().fit(daily_returns).covariance_,len(assets),0,axis=0)),len(assets),0,axis=1)
,columns=daily_returns_b.columns,index=daily_returns_b.columns)
robust_cov_matrix_b
Out[17]:
In [18]:
num_portfolios = 200000
num_assets=len(assets)
r=0.0001
weights = np.array(np.random.random(num_assets*num_portfolios)).reshape(num_portfolios,num_assets)
weights = weights*np.matlib.repmat(1/weights.sum(axis=1),num_assets,1).T
rend=252*weights.dot(mean_daily_returns.values[:,0]).T
sd = np.zeros(num_portfolios)
for i in range(num_portfolios):
sd[i]=np.sqrt(252*(((weights[i,:]).dot(robust_cov_matrix)).dot(weights[i,:].T)))
sharpe=np.divide((rend-r),sd)
results_frame = pd.DataFrame(data=np.column_stack((rend,sd,sharpe,weights)),columns=(['Rendimiento','SD','Sharpe']+list(daily_returns.columns)))
In [19]:
#Sharpe Ratio
max_sharpe_port = results_frame.iloc[results_frame['Sharpe'].idxmax()]
#Menor SD
min_vol_port = results_frame.iloc[results_frame['SD'].idxmin()]
In [20]:
plt.scatter(results_frame.SD,results_frame.Rendimiento,c=results_frame.Sharpe,cmap='RdYlBu')
plt.xlabel('Volatility')
plt.ylabel('Returns')
plt.colorbar()
#Sharpe Ratio
plt.scatter(max_sharpe_port[1],max_sharpe_port[0],marker=(5,1,0),color='r',s=1000);
#Menor SD
plt.scatter(min_vol_port[1],min_vol_port[0],marker=(5,1,0),color='g',s=1000);
In [21]:
pd.DataFrame(max_sharpe_port)
Out[21]:
In [22]:
pd.DataFrame(min_vol_port)
Out[22]:
In [23]:
num_assets_b=len(assets)+1
weights_b = np.array(np.random.random(num_assets_b*num_portfolios)).reshape(num_portfolios,num_assets_b)
weights_b[0:int(num_portfolios/5),-1]=weights_b[0:int(num_portfolios/5),-1]+5
weights_b = weights_b*np.matlib.repmat(1/weights_b.sum(axis=1),num_assets_b,1).T
weights_b[0,:]=np.zeros(num_assets_b)
weights_b[0,:][-1]=1
rend_b=252*weights_b.dot(mean_daily_returns_b.values[:,0]).T
sd_b = np.zeros(num_portfolios)
for i in range(num_portfolios):
sd_b[i]=np.sqrt(252*(((weights_b[i,:]).dot(robust_cov_matrix_b)).dot(weights_b[i,:].T)))
sharpe_b = np.zeros(num_portfolios)
sharpe_b[1:]=np.divide((rend_b[1:]-r),sd_b[1:])
results_frame_b = pd.DataFrame(data=np.column_stack((rend_b,sd_b,sharpe_b,weights_b)),columns=(['Rendimiento','SD','Sharpe']+list(daily_returns_b.columns)))
In [24]:
#Sharpe Ratio
max_sharpe_port_b = results_frame_b.iloc[results_frame_b['Sharpe'].idxmax()]
#Menor SD
min_vol_port_b = results_frame_b.iloc[results_frame_b['SD'].idxmin()]
In [25]:
plt.scatter(results_frame_b.SD,results_frame_b.Rendimiento,c=results_frame_b.Sharpe,cmap='RdYlBu')
plt.xlabel('Volatility')
plt.ylabel('Returns')
plt.colorbar()
#Sharpe Ratio
plt.scatter(max_sharpe_port_b[1],max_sharpe_port_b[0],marker=(5,1,0),color='r',s=1000);
#Menor SD
plt.scatter(min_vol_port_b[1],min_vol_port_b[0],marker=(5,1,0),color='g',s=1000);
In [26]:
pd.DataFrame(max_sharpe_port_b)
Out[26]:
In [27]:
pd.DataFrame(min_vol_port_b)
Out[27]:
In [28]:
def sim_mont_portfolio(daily_returns,num_portfolios,risk_free):
num_assets=len(daily_returns.T)
#Packages
import pandas as pd
import sklearn.covariance as skcov
import statsmodels.api as sm
huber = sm.robust.scale.Huber()
#Mean and standar deviation returns
returns_av, scale = huber(daily_returns)
#returns_av = daily_returns.mean()
covariance= skcov.ShrunkCovariance().fit(daily_returns).covariance_
#Simulated weights
weights = np.array(np.random.random(num_assets*num_portfolios)).reshape(num_portfolios,num_assets)
weights = weights*np.matlib.repmat(1/weights.sum(axis=1),num_assets,1).T
ret=252*weights.dot(returns_av).T
sd = np.zeros(num_portfolios)
for i in range(num_portfolios):
sd[i]=np.sqrt(252*(((weights[i,:]).dot(covariance)).dot(weights[i,:].T)))
sharpe=np.divide((ret-risk_free),sd)
return pd.DataFrame(data=np.column_stack((ret,sd,sharpe,weights)),columns=(['Returns','SD','Sharpe']+list(daily_returns.columns)))
In [29]:
results_frame = sim_mont_portfolio(daily_returns,200000,r)
In [30]:
#Sharpe Ratio
max_sharpe_port = results_frame.iloc[results_frame['Sharpe'].idxmax()]
#Menor SD
min_vol_port = results_frame.iloc[results_frame['SD'].idxmin()]
In [31]:
plt.scatter(results_frame.SD,results_frame.Returns,c=results_frame.Sharpe,cmap='RdYlBu')
plt.xlabel('Volatility')
plt.ylabel('Returns')
plt.colorbar()
#Sharpe Ratio
plt.scatter(max_sharpe_port[1],max_sharpe_port[0],marker=(5,1,0),color='r',s=1000);
#Menor SD
plt.scatter(min_vol_port[1],min_vol_port[0],marker=(5,1,0),color='g',s=1000);
In [32]:
pd.DataFrame(max_sharpe_port)
Out[32]:
In [33]:
pd.DataFrame(min_vol_port)
Out[33]:
In [80]:
import sim_mont_portfolio_py
In [83]:
sim_mont_portfolio_py.sim_mont_portfolio(daily_returns,2000,r)
Out[83]:
In [ ]: