12 Monos

Gerard Sánchez - 16 de Noviembre de 2021 a las 12:08 - Random




"Un chimpancé lanzando dardos sobre una página de cotizaciones sería capaz de seleccionar una cartera más rentable que la mayoría". 

Quien supera al mercado, ¿lo supera porque realiza correctamente la selección de empresas y el momento en el que invertir o es porque estadísticamente le ha tocado?

En este artículo vamos a replicar el experimento que trató de refutar la crítica del norteamericano Burton Gordon Malkiel en 1973, en el que afirmaba que un mono lanzando dardos sería capaz de tener unos retornos similares al resto de gestores.

La idea es generar aleatoriamente 12 carteras de 10 activos, ponderadas por igual, y calcular la rentabilidad media para el periodo.

Veamos el código:

Vamos a necesitar random para la selección al azar y probablemente consigamos mayor eficiencia utilizando yfinance para la descarga de precios que con pandas_datareader.

import pandas as pd
import random
import yahoo_fin.stock_info as si
import matplotlib.pyplot as plt
import yfinance as yf

Creamos las variables a utilizar y un DataFrame llamado monos que va a contener nuestras 12 carteras con 10 activos con sus respectivos retornos y la rentabilidad media.

tickers=[]
tabla=[]
ticks=[0]*10
barras=[]

monos=pd.DataFrame(columns=['Random 1','Random 2','Random 3',
'Random 4','Random 5','Random 6','Random 7',
'Random 8','Random 9','Random 10','Rent.md.'], index=range(24))

Con yahoo_fin.stock_info utilizo el método tickers_sp500() para tener todos mis activos en una lista.

lt = si.tickers_sp500()

Básicamente he decidido crear un DataFrame de 24 filas y tener cada ticker con su rentabilidad. En la variable ticks utilizamos el método random.sample, para seleccionar 10 números sobre una lista de 500, y luego con otro bucle hacemos 10 iteraciones para añadir los 10 tickers a los que corresponden esos números y descargamos los precios de cierre para el periodo considerado.

for m in range(0,24,2):
    print('Mono ',m//2)
    ticks=random.sample(range(len(lt)),10)
    for i in range(10):
        tickers.append(lt[ticks[i]])
    df = yf.download(tickers,auto_adjust=False,start="2021-01-01")['Close']

A continuación rellenamos una variable con append con el cálculo de los retornos de cada activo y completamos el DataFrame de monos de forma intercalada, partiendo del bucle for m in range(0,24,2), y reiniciamos nuestras variables (las vaciamos) para iniciar otra recursión.

Finalmente una fila con tickers y otra con los retornos, únicamente nos quedará calcular la rentabilidad media.

    for i in range(10):
        tabla.append(round(float(df.iloc[(len(df)-1),i]/df.iloc[0,i]-1)*100,2))
        monos.iloc[m,i]=tickers[i]
        monos.iloc[(m+1),i]=tabla[i]
    tickers=[]  
    tabla=[]

Siguiendo este esquema de bucles, calculamos la suma de los retornos de los 10 activos de cada cartera y luego dividimos entre 10, ya que cada activo tiene el mismo peso, lo pasamos a una lista barras que luego graficaremos, y rellenamos esa columna al DataFrame de monos

suma=float(0)
for i in range(0,24,2):
    for n in range(10):
        suma=suma+float(monos.iloc[(i+1),n]) 
    suma=round(float(suma)/10,2)
    barras.append(suma) 
    monos.iloc[i+1,10]=suma 
    monos.iloc[(i),10]=('Mono: ',i//2+1)
    suma=0

Finalmente nos queda graficar esa columna con la rentabilidad media.

Genero un índice para el gráfico con "Monos x" y grafico barras que es donde he pasado mi variable suma con las rentabilidades medias.

monos2 = []
for x in range(12):
    monos2.append("Mono/s "+str(x+1))

plt.figure(figsize=(16,8))
plt.bar(monos2, barras)
plt.title('Rentabilidad de la cartera de cada mono')
plt.ylabel('Porcentaje %')
plt.xlabel('Monos')
plt.show()

Aquí tenéis el código completo:

import pandas as pd
import random
import yahoo_fin.stock_info as si
import matplotlib.pyplot as plt
import yfinance as yf

tickers=[]
tabla=[]
ticks=[0]*10
barras=[]
monos=pd.DataFrame(columns=['Random 1','Random 2','Random 3',
'Random 4','Random 5','Random 6','Random 7',
'Random 8','Random 9','Random 10','Rent.md.'], index=range(24))

lt = si.tickers_sp500()

for m in range(0,24,2):
    print('Mono ',m//2)
    ticks=random.sample(range(len(lt)),10)
    for i in range(10):
        tickers.append(lt[ticks[i]])
    df = yf.download(tickers,auto_adjust=False,start="2021-01-01")['Close']
    for i in range(10):
        tabla.append(round(float(df.iloc[(len(df)-1),i]/df.iloc[0,i]-1)*100,2))
        monos.iloc[m,i]=tickers[i]
        monos.iloc[(m+1),i]=tabla[i]
    tickers=[]  
    tabla=[] 

suma=float(0)

for i in range(0,24,2):
    for n in range(10):
        suma=suma+float(monos.iloc[(i+1),n]) 
    suma=round(float(suma)/10,2)
    barras.append(suma) 
    monos.iloc[i+1,10]=suma 
    monos.iloc[(i),10]=('Mono: ',i//2+1)
    suma=0

print(monos)

monos2 = []
for x in range(12):
    monos2.append("Mono/s "+str(x+1))

plt.figure(figsize=(16,8))
plt.bar(monos2, barras)
plt.title('Rentabilidad de la cartera de cada mono')
plt.ylabel('Porcentaje %')
plt.xlabel('Monos')
plt.show()

923 visitas
2    Login to like
Categorías:
 Estrategias   Estadísticas   Random   Gestión pasiva   Análisis técnico   Modelos   CEO   Mapas mentales   Liberalismo   Python   Growth   Niusleta   Ahorro   Recursos humanos   Inmobiliario   Fiscalidad   Value investing   Dividendos   Contabilidad   Marketing   Riesgo   IF   Cursos   Opciones   Bolsa