0% found this document useful (0 votes)
8 views1 page

Gestión de Carteras Mapa de Calor

The document outlines a portfolio management process using Python libraries to analyze stock data, calculate returns, and optimize portfolios. It includes steps for importing data, calculating expected returns and volatility, and creating random portfolios, followed by optimization for maximum Sharpe ratio and minimum variance. The final output includes efficient frontier calculations and visualizations of expected returns versus volatility.

Uploaded by

Sergio García
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views1 page

Gestión de Carteras Mapa de Calor

The document outlines a portfolio management process using Python libraries to analyze stock data, calculate returns, and optimize portfolios. It includes steps for importing data, calculating expected returns and volatility, and creating random portfolios, followed by optimization for maximum Sharpe ratio and minimum variance. The final output includes efficient frontier calculations and visualizations of expected returns versus volatility.

Uploaded by

Sergio García
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

Gestión de carteras

Importamos librerias
In [1]: import math
import numpy as np
import scipy.stats as scs
import statsmodels.api as sm
import pandas as pd
from pylab import mpl, plt

Definimos las características de los gráficos


In [39]: plt.style.use('seaborn')#color
mpl.rcParams['font.family'] = 'serif' #tipo de letra
%matplotlib inline

Recuperamos precios y calculamos rentabilidades


In [40]: filename='/Users/sergio/Downloads/tr_eikon_eod_data (1).csv' #definimos la ruta del archivo
raw = pd.read_csv(filename, index_col=0, parse_dates=True) #importar archivo (estructura panda),(archivo, columna 0
#desde panda, debemos decir que son verdaderos los datos, ya que son fechas, convencer a pandas de que son fechas)
print(raw)

AAPL.O MSFT.O INTC.O AMZN.O GS.N SPY .SPX \


Date
2010-01-01 NaN NaN NaN NaN NaN NaN NaN
2010-01-04 30.572827 30.950 20.88 133.90 173.08 113.33 1132.99
2010-01-05 30.625684 30.960 20.87 134.69 176.14 113.63 1136.52
2010-01-06 30.138541 30.770 20.80 132.25 174.26 113.71 1137.14
2010-01-07 30.082827 30.452 20.60 130.00 177.67 114.19 1141.69
... ... ... ... ... ... ... ...
2018-06-25 182.170000 98.390 50.71 1663.15 221.54 271.00 2717.07
2018-06-26 184.430000 99.080 49.67 1691.09 221.58 271.60 2723.06
2018-06-27 184.160000 97.540 48.76 1660.51 220.18 269.35 2699.63
2018-06-28 185.500000 98.630 49.25 1701.45 223.42 270.89 2716.31
2018-06-29 185.110000 98.610 49.71 1699.80 220.57 271.28 2718.37

.VIX EUR= XAU= GDX GLD


Date
2010-01-01 NaN 1.4323 1096.35 NaN NaN
2010-01-04 20.04 1.4411 1120.00 47.71 109.80
2010-01-05 19.35 1.4368 1118.65 48.17 109.70
2010-01-06 19.16 1.4412 1138.50 49.34 111.51
2010-01-07 19.06 1.4318 1131.90 49.10 110.82
... ... ... ... ... ...
2018-06-25 17.33 1.1702 1265.00 22.01 119.89
2018-06-26 15.92 1.1645 1258.64 21.95 119.26
2018-06-27 17.91 1.1552 1251.62 21.81 118.58
2018-06-28 16.85 1.1567 1247.88 21.93 118.22
2018-06-29 16.09 1.1683 1252.25 22.31 118.65

[2216 rows x 12 columns]

In [48]: symbols = ['SPY', 'GLD', 'AAPL.O', 'MSFT.O'] #definición de un vector con los activos que queremos (comillas individuales)
data = (pd.DataFrame(raw[symbols].dropna()))
print(data)

SPY GLD AAPL.O MSFT.O


Date
2010-01-04 113.33 109.80 30.572827 30.950
2010-01-05 113.63 109.70 30.625684 30.960
2010-01-06 113.71 111.51 30.138541 30.770
2010-01-07 114.19 110.82 30.082827 30.452
2010-01-08 114.57 111.37 30.282827 30.660
... ... ... ... ...
2018-06-25 271.00 119.89 182.170000 98.390
2018-06-26 271.60 119.26 184.430000 99.080
2018-06-27 269.35 118.58 184.160000 97.540
2018-06-28 270.89 118.22 185.500000 98.630
2018-06-29 271.28 118.65 185.110000 98.610

[2138 rows x 4 columns]

Creamos una cartera aleatoria con cuatro títulos


In [64]: noa = len(symbols) #Creamos una cartera con 4 títulos len cuenta el numero de datos que hay en el vector

In [53]: rets=np.log(data).diff().dropna()

In [54]: rets.mean() * 252

SPY 0.102928
Out[54]:
GLD 0.009141
AAPL.O 0.212359
MSFT.O 0.136648
dtype: float64

In [55]: rets.cov() * 252 #matriz de varianzas y covarianzas

Out[55]: SPY GLD AAPL.O MSFT.O

SPY 0.021939 0.000062 0.021039 0.022244

GLD 0.000062 0.026209 0.001513 -0.000347

AAPL.O 0.021039 0.001513 0.063773 0.023427

MSFT.O 0.022244 -0.000347 0.023427 0.050917

In [56]: weights = np.random.random(noa) #DEFINIMOS UN VECTOR, NUMPY biblioteca de funciones matemáticas, random son funciones aleatorias
print(weights)

[0.5726141 0.26983853 0.27609188 0.0207017 ]

In [57]: weights /= np.sum(weights) #dividimos por la suma de los pesos


print(weights)

[0.50262542 0.23685708 0.24234611 0.0181714 ]

In [58]: np.dot(rets.mean().T *252, weights) #calculamos la rentabilidad multiplicando las rentabilidades medias
#transponemos la matriz de las medias y se multiplica por los pesos de manera aleatoria

0.10784694169942974
Out[58]:

In [59]: np.dot(weights.T, np.dot(rets.cov() * 252, weights)) #calculamos la varianza

0.016698627439456583
Out[59]:

In [60]: math.sqrt(np.dot(weights.T, np.dot(rets.cov() * 252, weights))) # desviación típica,


#importamos la función raiz cuadrada de la libreria math

0.1292231691278951
Out[60]:

In [61]: def port_ret(weights): #definimos una función portfolio returns, sujeta a los parámetros (weights) precisa de la sangría (:)
return np.dot(rets.mean().T *252, weights)

In [62]: def port_vol(weights): #desviación típica


return np.sqrt(np.dot(weights.T, np.dot(rets.cov() * 252, weights)))

In [63]: prets = [] #se van guardando los datos de cada resultado de un bucle
pvols = []

In [65]: for p in range (2500): #definimos el bucle, empezamos en p(o cualquier letra)(0) y terminamos en 2500
weights = np.random.random(noa)
weights /= np.sum(weights)
prets.append(port_ret(weights)) #dentro de la caja donde se guardan los datos, agregando datos a la lista
pvols.append(port_vol(weights))

In [66]: prets = np.array(prets) #convertimos la caja donde se guardan los datos en un vector
pvols = np.array(pvols)

In [67]: plt.figure(figsize=(10, 6))#tamaño


plt.scatter(pvols, prets, c=prets / pvols, marker='o', cmap='coolwarm')#scatter graph, eje x, eje y, c es ratio de sharpe, marcador de puntos (o), mapa de calor dependi
plt.xlabel('expected volatility')#definimos los ejes
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio')

/var/folders/6f/s02w999d14zfv3n6n4fchypw0000gn/T/ipykernel_37068/2553437515.py:5: MatplotlibDeprecationWarning: Auto-removal of grids by pcolor() and pcolormesh() is de


precated since 3.5 and will be removed two minor releases later; please call grid(False) first.
plt.colorbar(label='Sharpe ratio')
<matplotlib.colorbar.Colorbar at 0x7fc4caa54ac0>
Out[67]:

Cartera eficiente para c=0


In [68]: import scipy.optimize as sco

In [69]: def min_func_sharpe(weights):


return -port_ret(weights) / port_vol(weights)

In [70]: bnds = tuple((0, 1) for x in range(noa))


cons = ({'type': 'eq', 'fun': lambda x:np.sum(x) - 1})
eweights = np.array(noa * [1. / noa,])
eweights

array([0.25, 0.25, 0.25, 0.25])


Out[70]:

In [71]: min_func_sharpe(eweights)

-0.8436203363155412
Out[71]:

In [72]: opts = sco.minimize(min_func_sharpe, eweights, method='SLSQP', bounds=bnds, constraints=cons)


opts

fun: -0.8976673894091783
Out[72]:
jac: array([-2.45951116e-04, 1.93044543e-05, 8.96826386e-05, 8.30516219e-05])
message: 'Optimization terminated successfully'
nfev: 30
nit: 6
njev: 6
status: 0
success: True
x: array([0.25454109, 0.04228126, 0.51191352, 0.19126413])

In [73]: opts['x'].round(3)

array([0.255, 0.042, 0.512, 0.191])


Out[73]:

In [74]: port_ret(opts['x']).round(3)

0.161
Out[74]:

In [75]: port_vol(opts['x']).round(3)

0.18
Out[75]:

In [76]: port_ret(opts['x']) / port_vol(opts['x'])

0.8976673894091783
Out[76]:

Cartera de Mínima Varianza


In [77]: optv = sco.minimize(port_vol, eweights, method='SLSQP', bounds=bnds, constraints=cons)
optv

fun: 0.10942155263366907
Out[77]:
jac: array([0.10939826, 0.10944918, 0.11098003, 0.10948556])
message: 'Optimization terminated successfully'
nfev: 45
nit: 9
njev: 9
status: 0
success: True
x: array([0.54326308, 0.45567521, 0. , 0.0010617 ])

In [78]: optv['x'].round(3)

array([0.543, 0.456, 0. , 0.001])


Out[78]:

In [79]: port_ret(optv['x']).round(3)

0.06
Out[79]:

In [80]: port_vol(optv['x']).round(3)

0.109
Out[80]:

In [81]: port_ret(optv['x']) / port_vol(optv['x'])

0.5504173647607122
Out[81]:

Frontera eficiente
In [82]: cons = ({'type': 'eq', 'fun': lambda x: port_ret(x) - tret},
{'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
bnds = tuple((0, 1) for x in weights)

In [84]: trets = np.linspace(0.05, 0.2, 50)


tvols = []
for tret in trets:
res = sco.minimize(port_vol, eweights, method='SLSQP',bounds=bnds, constraints=cons)
tvols.append(res['fun'])
tvols = np.array(tvols)

In [85]: print(tvols)

[0.11198911 0.11068712 0.10983644 0.10944758 0.10947297 0.10969286


0.11008001 0.11063305 0.11134938 0.11222585 0.11325876 0.11444387
0.1157765 0.11725162 0.11886393 0.12060837 0.12247811 0.12446845
0.12657361 0.12878784 0.13110569 0.13352186 0.13603043 0.13862715
0.14130693 0.14406512 0.1468973 0.14979927 0.15276706 0.1557969
0.15888524 0.1620288 0.16522477 0.16846903 0.17175966 0.17509422
0.17846999 0.18188458 0.18533589 0.18882214 0.19234281 0.19593905
0.19962547 0.20339717 0.20724919 0.21117744 0.21517764 0.21935776
0.22394705 0.22892911]

In [86]: plt.figure(figsize=(10, 6))


plt.scatter(pvols, prets, c=prets / pvols, marker='.', alpha=0.8, cmap='coolwarm')
plt.plot(tvols, trets, 'b', lw=4.0)
plt.plot(port_vol(opts['x']), port_ret(opts['x']),'y*', markersize=15.0)
plt.plot(port_vol(optv['x']), port_ret(optv['x']),'r*', markersize=15.0)
plt.xlabel('expected volatility')
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio')

/var/folders/6f/s02w999d14zfv3n6n4fchypw0000gn/T/ipykernel_37068/1389620534.py:8: MatplotlibDeprecationWarning: Auto-removal of grids by pcolor() and pcolormesh() is de


precated since 3.5 and will be removed two minor releases later; please call grid(False) first.
plt.colorbar(label='Sharpe ratio')
<matplotlib.colorbar.Colorbar at 0x7fc4caad3100>
Out[86]:

Linea del mercado de capitales


In [87]: import scipy.interpolate as sci

In [88]: ind = np.argmin(tvols)


print(ind)

In [89]: evols = tvols[ind:]


erets = trets[ind:]

In [90]: tck = sci.splrep(evols, erets)


tck

(array([0.10944758, 0.10944758, 0.10944758, 0.10944758, 0.10969286,


Out[90]:
0.11008001, 0.11063305, 0.11134938, 0.11222585, 0.11325876,
0.11444387, 0.1157765 , 0.11725162, 0.11886393, 0.12060837,
0.12247811, 0.12446845, 0.12657361, 0.12878784, 0.13110569,
0.13352186, 0.13603043, 0.13862715, 0.14130693, 0.14406512,
0.1468973 , 0.14979927, 0.15276706, 0.1557969 , 0.15888524,
0.1620288 , 0.16522477, 0.16846903, 0.17175966, 0.17509422,
0.17846999, 0.18188458, 0.18533589, 0.18882214, 0.19234281,
0.19593905, 0.19962547, 0.20339717, 0.20724919, 0.21117744,
0.21517764, 0.21935776, 0.22892911, 0.22892911, 0.22892911,
0.22892911]),
array([0.05918367, 0.07054273, 0.06082628, 0.07127788, 0.07083661,
0.07514943, 0.07767382, 0.08086119, 0.08383801, 0.08689314,
0.08992981, 0.09297762, 0.0960237 , 0.09907511, 0.1021263 ,
0.10517914, 0.10823306, 0.111288 , 0.11434291, 0.11739981,
0.12045623, 0.12351347, 0.12657107, 0.12962905, 0.13268735,
0.13574592, 0.13880476, 0.14186379, 0.14492335, 0.14798199,
0.15104218, 0.15410192, 0.15716163, 0.1602216 , 0.16328154,
0.1663424 , 0.16940089, 0.17248302, 0.17554844, 0.17860635,
0.18166469, 0.18472455, 0.18778021, 0.19088088, 0.19525889,
0.19809058, 0.2 , 0. , 0. , 0. ,
0. ]),
3)

In [91]: def f(x):


return sci.splev(x, tck, der=0)
def df(x):
return sci.splev(x, tck, der=1)

In [92]: def equations(p, rf=0.01):


eq1 = rf - p[0]
eq2 = rf + p[1] * p[2] - f(p[2])
eq3 = p[1] - df(p[2])
return eq1, eq2, eq3

In [93]: opt = sco.fsolve(equations, [0.01, 0.5, 0.15])

In [94]: opt

array([0.01 , 0.84470952, 0.19525392])


Out[94]:

In [95]: plt.figure(figsize=(10, 6))


plt.scatter(pvols, prets, c=(prets - 0.01) / pvols,marker='.', cmap='coolwarm')
plt.plot(evols, erets, 'b', lw=4.0)
cx = np.linspace(0.0, 0.3)
plt.plot(cx, opt[0] + opt[1] * cx, 'r', lw=1.5)
plt.plot(opt[2], f(opt[2]), 'y*', markersize=15.0)
plt.grid(True)
plt.axhline(0, color='k', ls='--', lw=2.0)
plt.axvline(0, color='k', ls='--', lw=2.0)
plt.xlabel('expected volatility')
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio')

/var/folders/6f/s02w999d14zfv3n6n4fchypw0000gn/T/ipykernel_37068/246825966.py:12: MatplotlibDeprecationWarning: Auto-removal of grids by pcolor() and pcolormesh() is de


precated since 3.5 and will be removed two minor releases later; please call grid(False) first.
plt.colorbar(label='Sharpe ratio')
<matplotlib.colorbar.Colorbar at 0x7fc4b93ad6a0>
Out[95]:

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy