3 votos

La frontera eficiente no tiene buena pinta

Hola estoy intentando dibujar una frontera eficiente. A continuación se muestra lo que he utilizado. El parámetro de retornos consiste en 9 columnas de retornos de cartera. Seleccioné 10.000 carteras y así es como quedó mi frontera eficiente. Esta no es la forma de frontera habitual que nos es familiar.

El conjunto de datos es 48_Industry_Portfolios_daily.csv, obtenido de ( http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html ). Se seleccionaron las 9 primeras columnas

¿Puede alguien explicarme el problema?

def portfolio_annualised_performance(weights, mean_returns, cov_matrix):
    returns = np.sum(mean_returns*weights ) *252
    #print ('weights shape',weights.shape)
    #print (' Returns ',returns)
    std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
    #print ('Std ',std)
    return std, returns

def random_portfolios(num_portfolios, mean_returns, cov_matrix, risk_free_rate):
    results = np.zeros((3,num_portfolios))
    weights_record = []
    for i in range(num_portfolios):
        weights = np.random.random(48)

        weights /= np.sum(weights)
        weights_record.append(weights)
        portfolio_std_dev, portfolio_return = portfolio_annualised_performance(weights, mean_returns, cov_matrix)
        results[0,i] = portfolio_std_dev
        results[1,i] = portfolio_return
        results[2,i] = (portfolio_return - risk_free_rate) / portfolio_std_dev
    return results, weights_record

def monteCarlo_Simulation(returns):

    #returns=returns.drop("Date")
    returns=returns/100
    stocks=list(returns)
    stocks1=list(returns)
    stocks1.insert(0,"ret")
    stocks1.insert(1,"stdev")
    stocks1.insert(2,"sharpe")
    print (stocks)
    #calculate mean daily return and covariance of daily returns
    mean_daily_returns = returns.mean()
    #print (mean_daily_returns)
    cov_matrix = returns.cov()

    #set number of runs of random portfolio weights
    num_portfolios = 10000

    #set up array to hold results
    #We have increased the size of the array to hold the weight values for each stock
    results = np.zeros((4+len(stocks)-1,num_portfolios))

    for i in range(num_portfolios):
        #select random weights for portfolio holdings
        weights = np.array(np.random.random(len(stocks)))
        #rebalance weights to sum to 1
        weights /= np.sum(weights)

        #calculate portfolio return and volatility
        portfolio_return = np.sum(mean_daily_returns * weights) * 252
        portfolio_std_dev = np.sqrt(np.dot(weights.T,np.dot(cov_matrix, weights))) * np.sqrt(252)

        #store results in results array
        results[0,i] = portfolio_return
        results[1,i] = portfolio_std_dev
        #store Sharpe Ratio (return / volatility) - risk free rate element excluded for simplicity
        results[2,i] = results[0,i] / results[1,i]
        #iterate through the weight vector and add data to results array
        for j in range(len(weights)):
            results[j+3,i] = weights[j]

    print (results.T.shape)
    #convert results array to Pandas DataFrame
    results_frame = pd.DataFrame(results.T,columns=stocks1)

    #locate position of portfolio with highest Sharpe Ratio
    max_sharpe_port = results_frame.iloc[results_frame['sharpe'].idxmax()]
    #locate positon of portfolio with minimum standard deviation
    min_vol_port = results_frame.iloc[results_frame['stdev'].idxmin()]

    #create scatter plot coloured by Sharpe Ratio
    plt.figure(figsize=(10,10))
    plt.scatter(results_frame.stdev,results_frame.ret,c=results_frame.sharpe,cmap='RdYlBu')
    plt.xlabel('Volatility')
    plt.ylabel('Returns')
    plt.colorbar()
    #plot red star to highlight position of portfolio with highest Sharpe Ratio
    plt.scatter(max_sharpe_port[1],max_sharpe_port[0],marker=(2,1,0),color='r',s=1000)
    #plot green star to highlight position of minimum variance portfolio
    plt.scatter(min_vol_port[1],min_vol_port[0],marker=(2,1,0),color='g',s=1000)

    print(max_sharpe_port)

enter image description here

enter image description here

respuesta actualizada

enter image description here

También me piden que compare la varianza de la cartera utilizando diferentes regularizaciones y que utilice un método de validación para encontrar los parámetros óptimos. ¿Podemos utilizar python para hacer esto?

2 votos

Sería de gran ayuda que otros tuvieran tu parámetro returns para poder ejecutar el código y depurarlo.

0 votos

¿Hay alguna forma de adjuntar mi excel?

0 votos

Puedes subir un csv a algún sitio y enlazarlo.

6voto

Sideshow Bob Puntos 167

Por lo que entiendo de su pregunta, no entiende por qué no se representa claramente la forma de parábola de la frontera.

Si quieres ver la forma con más claridad, puedes hacer una de estas dos cosas:

  1. Aumentar el número de carteras aleatorias. A medida que este número se eleve hasta el infinito, acabará trazando todas las combinaciones posibles de carteras y su frontera eficiente será muy visible.

  2. Utilice el hecho de que todas las carteras de la frontera eficiente se pueden construir mediante combinaciones de sólo dos carteras eficientes (por ejemplo, las carteras de sharpe máximo y varianza mínima). Para ello, basta con construir una matriz de carteras ((rentabilidad, desviación típica)-pares) con ponderaciones iguales a $weights=w*\pi_{max}+(1-w)*\pi_{min}$ para un intervalo de $w$ 's.

En lugar de crear 10.000 carteras aleatorias para hallar las carteras de tangencia y var.mín., también podrías resolverlas utilizando las ecuaciones

$$ \mathbf{\pi}_{\max SR} = \frac{1}{\mathbf{1'\Sigma^{-1}\mu}} \mathbf{\Sigma^{-1}\mu}$$

$$ \mathbf{\pi_{\min Var}} = \frac{1}{ \mathbf{1' \Sigma^{-1}1}} \mathbf{ \Sigma^{-1}1}$$

Dónde $\mathbf{\Sigma^{-1}}$ es la inversa de su matriz de varianza-covarianza, $\mathbf{\mu}$ es su vector de rendimientos esperados, y $\mathbf{1}$ es un vector de 1's con la misma longitud que su $\mathbf{\mu}$ .

0 votos

Además, si realmente quieres resaltar visualmente la curva de la frontera, puedes cambiar la relación de aspecto del gráfico para hacerlo más ancho.

0 votos

Hola JTHG. Muchas gracias por la respuesta. Bueno he pasado por el primer paso. todavía la frontera no se parece a una parábola. Tomé 500.000 carteras. Lo actualicé en mi respuesta

0 votos

Deberías intentar hacer el paso 2 y superponerlo en el gráfico para ver cómo debería quedar. Creo que la forma es un poco confuso, pero es definitivamente allí en su respuesta actualizada.

3voto

Arlene Serrano Puntos 6

La razón por la que la frontera eficiente no se ve bien es porque No es la frontera eficiente. Es la conjunto factible .

Lo que hace tu código es generar carteras aleatorias e introduciendo estos vectores de pesos aleatorios en la función fórmula del modelo de media-varianza. Estas carteras aleatorias, transformadas así a coordenadas de varianza media, sólo proporcionan el conjunto factible que son carteras inferiores a la frontera eficiente (vista como todo lo que hay en la nube a la derecha del límite izquierdo), y por casualidad muchas carteras muy cercanas o a lo largo de la frontera eficiente si se genera un número suficientemente alto de ellas. Pero no es la forma directa de resolver el frontera eficiente separado del conjunto factible.

Para trazar la frontera eficiente, hay que resolver para carteras óptimas a lo largo de la frontera eficiente directamente, lo que requiere una optimización convexa de la fórmula del modelo de varianza media,

$$\min_w w^\top \Sigma w \enspace \hspace{2cm} \text{s.t.} \enspace w^\top \mu = \theta, \enspace \sum_{i=1}^N w_i=1 $$

Optimización de la fórmula anterior con un optimizador para distintos niveles de rentabilidad objetivo $\theta$ dará como resultado un vector de pesos óptimo como salida . Como puede ver, este procedimiento es no es lo mismo como introducir pesos aleatorios como entradas en la misma fórmula que en el enfoque de carteras aleatorias.

En resumen, actualmente está aplicando el primero de los dos enfoques siguientes,

Carteras aleatorias :

  • utilizar generados aleatoriamente pesos como entradas para la fórmula media-varianza
  • Todas las soluciones son sólo carteras viables (y si algunas son carteras eficientes, es por casualidad)

Carteras optimizadas :

  • utilizar el propio modelo de media-varianza para resolver el óptimo pesos como salidas
  • Todas las soluciones son carteras eficientes

Seguir el enfoque 1 explica el elevado número de carteras que aparecen en el extremo derecho, creando una nube circular, siendo el conjunto factible, a un tamaño de número de activos tan elevado (48), lo que los demás comentarios han señalado que ocurre por naturaleza. Reducir el tamaño de la cartera (10 o menos), independientemente de si es lo que quieres, es la única forma de reducir el número de carteras factibles "periféricas" que aparecen en el extremo derecho del conjunto factible si insistes en el uso del enfoque 1 (carteras factibles aleatorias) en lugar del enfoque 2 (carteras eficientes optimizadas).

2voto

dotnetcoder Puntos 1262

Aunque esto no responde a tu pregunta, quizá te interese saber que puedes vectorizar tu simulación y mejorar enormemente la eficiencia de tu código de esta forma:

def portfolio_annualised_performance(weights, mean_returns, cov_matrix):
    """
    Return annualised risk and return for a portfolio given asset weights and expected return and covriance

    Args:
        weights (ndarray): asset weights
        mean_returns (ndarray): expected returns of each asset
        cov_matrix (ndarray): covariance metrix of asset returns

    Returns:
        tuple: annualised risk (np.float64), annualised total return (np.float64)

    Notes:
        If weights is supplied as a 2D array, then outputs are not floats but 1D arrays.
    """
    return (np.sqrt(np.einsum('...i,ij,...j->...', weights, cov_matrix, weights) * 252),
            np.einsum('...i,i->...', weights, mean_returns) * 252)

def random_portfolios(size, mean_returns, cov_matrix, risk_free_rate):
    """
    Simulates a number of portfolio through random weights and calculates performance metrics

    Args:
        size (int): number of simulations
        mean_returns (ndarray): expected returns of each asset
        cov_matrix (ndarray): covariance metrix of asset returns
        risk_free_rate (np.float64): annualised risk free return

    Returns:
        tuple: annualised risk (ndarray), annualised total return (ndarray), Sharpe ratio (ndarray), weights (ndarray)
    """
    rand_weights = np.random.random(size=(size*mean_returns.shape[0])).reshape(size, -1)
    rand_weights /= np.sum(rand_weights, axis=1)[:, np.newaxis]
    perf = portfolio_annualised_performance(rand_weights, mean_returns, cov_matrix)
    return perf + ((perf[1] - risk_free_rate)/perf[0], rand_weights)

1voto

Alexander Abramov Puntos 603

Esto también me ha ocurrido a mí al intentar simular la frontera eficiente. La conclusión a la que llegué fue que a medida que aumento el número de instrumentos que intento utilizar, la frontera pierde su forma. Si quieres comprobar que tu código es correcto, simplemente deja 2-3 instrumentos, mira los resultados que salen, estoy bastante seguro de que verás que sale la forma habitual.

0 votos

Hola Gracias por responder. ¿A qué te refieres con instrumentos? ¿Es el número de carteras?

1 votos

Número de acciones/sectores/bonos que utiliza para obtener la frontera eficiente. Creo que está utilizando 9 de ellos.

0 votos

Una conjetura: la cartera óptima suele arrojar resultados muy concentrados (asigna ponderaciones <> 0 sólo a unos pocos sectores); cuando se utilizan muchos sectores, las ponderaciones aleatorias no asignan esa cantidad de 0, por lo que la forma se ve rara, pero el código es totalmente correcto, es sólo una simulación.

0voto

ben Heo Puntos 6

Dado que la primera parte de su pregunta ya ha sido respondida, le proporciono una solución para la segunda parte " También me piden que compare la varianza de la cartera utilizando diferentes regularizaciones y que utilice métodos de validación para encontrar los parámetros óptimos. ¿Podemos utilizar python para hacer esto? "

Puede realizar la regularización con 3 técnicas: Ridge (la regulacion ocurre añadiendo la suma de los pesos al cuadrado a la parte OLS), Lasso(la regulacion ocurre añadiendo la norma 1 de los pesos a la parte OLS) y ElasticNet regressions(la regulacion ocurre añadiendo ambas anteriores a la parte OLS). Para hacer esto necesitas codificar tu mismo esto durante la definición de tu problema de optimización. Para ejecutar tal optmimización puedes usar:

import cvxpy

Este es el paquete para la optimización convexa. No informo de la formulación matemática de la regularización ya que puedes encontrar toneladas de ellas en la web, sólo quiero mencionar que en Ridge y Lasso necesitas estimar un parámetro, mientras que en el ElasticNet necesitas estimar dos porque ElastcNet es una combinación de Lasso y Ridge. Esta contribución debe añadirse a la función de coste típica wT C w para minimizar.

Para la estimación del parámetro regularizado es necesario aplicar la validación cruzada. Puedes hacerlo en python. Se podría pensar en utilizar la validación cruzada k-fold, pero si se trata de datos de series temporales que tienen correlación serial no es lo ideal, ya que puede terminar teniendo muestras correlacionadas en el conjunto de prueba y entrenamiento, lo que puede causar un alto R cuadrado engañoso.

Así que le sugiero que utilice una versión modificada de K-fold llamada Purged with Embargo k-fold cross validation. Esto fue introducido por López de Prado en su sorprendente "Avances en el aprendizaje automático financiero" . La idea básica consiste en crear espacios entre los conjuntos de entrenamiento y de prueba mientras se dividen para reducir en la medida de lo posible el efecto de la correlación serial. Para implementar esta nueva versión de k-fold es necesario crear la clase para ello, ya que no está presente en sklearn. Pero el libro puede ayudar con esto también.

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X