8 votos

Carteras aleatorias frente a la frontera eficiente

Entiendo el concepto de frontera eficiente y soy capaz de calcularlo en Python. Pero incluso al generar 50'000 carteras aleatorias de 10 activos, las carteras individuales no se acercan siquiera a la frontera eficiente.

Veo que, por ejemplo, la cartera con máximo ratio de sharpe tiene una asignación muy pronunciada (la mayoría de los 10 activos tienen asignación 0).

Como este trabajo es muy crítico para mí, quería preguntar a la comunidad si habéis experimentado un comportamiento similar. ¿Es normal que al generar carteras aleatorias ni siquiera una se acerque a la frontera eficiente? Portfolios vs Efficient frontier

A continuación encontrará el código:

def portfolio_annualised_performance(weights, mean_returns, cov_matrix):
    returns = np.sum(mean_returns*weights )
    std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
    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 = abs(np.random.randn(len(mean_returns)))
        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 neg_sharpe_ratio(weights, mean_returns, cov_matrix, risk_free_rate):
    p_var, p_ret = portfolio_annualised_performance(weights, mean_returns, cov_matrix)
    return -(p_ret - risk_free_rate) / p_var

def max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix, risk_free_rate)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))
    result = sco.minimize(neg_sharpe_ratio, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)
    return result

def portfolio_volatility(weights, mean_returns, cov_matrix):
    return portfolio_annualised_performance(weights, mean_returns, cov_matrix)[0]

def min_variance(mean_returns, cov_matrix):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))

    result = sco.minimize(portfolio_volatility, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)
    return result

def efficient_return(mean_returns, cov_matrix, target):
    num_assets = len(mean_returns)
    args = (mean_returns, cov_matrix)

    def portfolio_return(weights):
        return portfolio_annualised_performance(weights, mean_returns, cov_matrix)[1]

    constraints = ({'type': 'eq', 'fun': lambda x: portfolio_return(x) - target},
                   {'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bounds = tuple((0.0,1) for asset in range(num_assets))
    result = sco.minimize(portfolio_volatility, num_assets*[1./num_assets,], args=args, method='SLSQP', bounds=bounds, constraints=constraints)
    return result

def efficient_frontier(mean_returns, cov_matrix, returns_range):
    efficients = []
    for ret in returns_range:
        efficients.append(efficient_return(mean_returns, cov_matrix, ret))
    return efficients

def display_calculated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate):
    results, _ = random_portfolios(num_portfolios,mean_returns, cov_matrix, risk_free_rate)

    max_sharpe = max_sharpe_ratio(mean_returns, cov_matrix, risk_free_rate)
    sdp, rp = portfolio_annualised_performance(max_sharpe['x'], mean_returns, cov_matrix)
    max_sharpe_allocation = pd.DataFrame(max_sharpe.x,index=curr_w_terms,columns=['allocation'])
    max_sharpe_allocation.allocation = [round(i*100,4)for i in max_sharpe_allocation.allocation]
    max_sharpe_allocation = max_sharpe_allocation.T

    min_vol = min_variance(mean_returns, cov_matrix)
    sdp_min, rp_min = portfolio_annualised_performance(min_vol['x'], mean_returns, cov_matrix)
    min_vol_allocation = pd.DataFrame(min_vol.x,index=curr_w_terms,columns=['allocation'])
    min_vol_allocation.allocation = [round(i*100,4)for i in min_vol_allocation.allocation]
    min_vol_allocation = min_vol_allocation.T

    print("-"*80)
    print("Maximum Sharpe Ratio Portfolio Allocation\n")
    print("Annualised Return:", round(rp,4))
    print("Annualised Volatility:", round(sdp,4))
    print("\n")
    print(max_sharpe_allocation)
    print("-"*80)
    print("Minimum Volatility Portfolio Allocation\n")
    print("Annualised Return:", round(rp_min,4))
    print("Annualised Volatility:", round(sdp_min,4))
    print("\n")
    print(min_vol_allocation)

    plt.figure(figsize=(10, 7))
    plt.scatter(results[0,:],results[1,:],c=results[2,:],cmap='YlGnBu', marker='o', s=10, alpha=0.3)
    plt.colorbar()
    plt.scatter(sdp,rp,marker='*',color='r',s=500, label='Maximum Sharpe ratio')
    plt.scatter(sdp_min,rp_min,marker='*',color='g',s=500, label='Minimum volatility')

    target = np.linspace(rp_min, 0.05, 20)
    efficient_portfolios = efficient_frontier(mean_returns, cov_matrix, target)
    plt.plot([p['fun'] for p in efficient_portfolios], target, linestyle='-.', color='black', label='efficient frontier')
    plt.title('Calculated Portfolio Optimization based on Efficient Frontier')
    plt.xlabel('annualised volatility')
    plt.ylabel('annualised returns')
    plt.legend(labelspacing=0.8)
    plt.ylim([-0.005,0.03])
    plt.xlim([0.0,0.05])

display_calculated_ef_with_random(log_ret, new_cov, 50000, 0)

No he anualizado la matriz Covar porque ya tengo estimaciones de rentabilidad anual además de las estimaciones Covar.

Mi pregunta es: ¿es esto plausible o no?

EDITAR Como el proceso de generación de pesos de mis carteras aleatorias parece preferir una cartera demasiado similar, he cambiado la siguiente función:

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 = abs(np.random.randn(len(mean_returns)))
        weights[weights<1] = 0
        if sum(weights)==0:
            print("sum=0")
            indexes = np.unique(np.random.randint(0,10,3)).tolist()
            weights[indexes] = abs(np.random.randn(len(indexes)))
        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

Después de hacerlo, las carteras están mucho mejor distribuidas:

Portfolios after new weighting scheme

Entonces, ¿podemos estar de acuerdo en que el código anterior hace lo que debe y puedo continuar desde aquí?

0 votos

No me gusta su método para generar pesos aleatorios. Está sesgado hacia la cartera de igual peso y no cubre todo el simplex de manera uniforme.

0 votos

¿alguna sugerencia de cómo superar esto?

0 votos

¿Se trata únicamente de una cartera de bonos?

13voto

Lie Ryan Puntos 15629

Parece que tienes dos problemas distintos:

  1. Cómo generar carteras aleatorias
  2. Cómo se estructuran las carteras óptimas

Anuncio 1)

Una forma sencilla de simular las ponderaciones de las carteras aleatorias es utilizar la distribución Dirichlet $Dir(\alpha_1,\ldots,\alpha_n)$ . Se trata de una distribución en el Simplex (es decir, en $S=\{x\in\mathbb{R}^n | \sum x_i =1, x_i\geq 0\}$ que pueden dar lugar a carteras muy diversificadas o muy concentradas. Fijar todos los $\alpha_i=1$ le da la distribución uniforme en el simplex, haciendo algunos $\alpha_i$ más pequeños le darán carteras concentradas en esos activos haciendo $\alpha_i$ asignaciones más amplias y diversificadas. Todos los datos pertinentes sobre $Dir(\alpha_1,\ldots,\alpha_n)$ se puede encontrar en el Artículo de Wikipedia .

A continuación se muestran dos gráficos de densidades para diferentes elecciones de una densidad de Dirichlet intercambiable para el Two-Simplex (que es un triángulo en el espacio): enter image description here

Anuncio 2)

Su cartera "óptima" dependerá de su criterio de optimización y de la rentabilidad conjunta de los activos. Así que dudo que alguien pueda hacer afirmaciones generales no triviales. Pero las carteras óptimas son, por definición, extremas. De ahí que no sea sorprendente que no sean genéricas. A juzgar por mi experiencia, el ratio de Sharpe favorece efectivamente las carteras muy desequilibradas y poco diversificadas.

0 votos

¿hay algún artículo que promueva el dirichlet para simular pesos aleatorios de cartera específicamente?

2voto

Corey Goldberg Puntos 15625

No es necesario inventar su propio algoritmo para las ponderaciones aleatorias de la cartera. Existe un algoritmo muy sencillo para generar un punto aleatorio en un simplex (es decir, para generar $e_i,i=1,k$ tal que $e_i\ge 0$ y $\sum_{i=1}^k e_i=1$ ). Se debe a Rubinstein y Melamed (1998):

  1. Generar k variables aleatorias exponenciales independientes $Y_1,\cdots,Y_k$ (por ejemplo, se pueden generar a partir de variables distribuidas uniformemente (0,1) U tomando $Y_i=-\ln(U_i)$ ).

  2. Calcule el total $T=\sum_{i=1}^k Y_i $

  3. Definir $E_i=Y_i/T$ y devolver $E$ como el vector deseado de pesos aleatorios de la cartera.

(Para una referencia publicada, véase este enlace https://ie.technion.ac.il/~onn/Selección/AOR09.pdf )

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