Estoy buscando generar rendimientos de acciones con correlación entre acciones en Python. Sin embargo, la salida no se está comportando correctamente y puede tener correlación temporal accidental causando problemas.
Este código está diseñado para generar número_de_caminos de los rendimientos correlacionados de las acciones dada una Serie de Panda de devuelve , un DataFrame de constante covarianzas y un DateIndex de fechas ( índice_de_fecha ).
from pandas import DataFrame, concat
from scipy.stats import multivariate_normal
def correlated_returns(num_paths, returns, covariances, date_index, periods_per_year=1):
period_returns = (1 + returns) ** (1 / periods_per_year) - 1 if periods_per_year != 1 else returns
mn = multivariate_normal(period_returns, covariances / periods_per_year, allow_singular=True)
digits = len(str(num_paths))
paths = [DataFrame(mn.rvs(size=len(date_index)), index=date_index, columns=returns.index) for _ in range(num_paths)]
keys = [f'Run {str(run_num).zfill(digits)}' for run_num in range(num_paths)]
return concat(paths, axis='columns', keys=keys, names=['Run', 'Returns'])
Mi código de prueba basado en la siguiente matriz de covarianza muestra algunas rarezas en los resultados que podrían estar relacionadas.
correlation = 0.2 # inter-stock correlation 0.18
annualized_return = 7 / 100 # Simulated return for each stock
stocks = [f'Stock {i}' for i in range(simulated_stocks)]
constituent_weights = DataFrame(1 / simulated_stocks, date_index, stocks)
returns = Series(annualized_return, stocks)
volatilities = Series(volatility, stocks)
correlations = DataFrame(correlation, stocks, stocks)
fill_diagonal(correlations.values, 1)
covariances = correlations.mul(volatilities, axis='index').mul(volatilities, axis='columns')
A lo largo de un gran número de simulaciones con igual pesos_constituyentes (arriba) el index_returns parecen estar negativamente autocorrelacionados (usando autocorr en Pandas). El rendimientos_anuales del índice son inferiores al 7% esperado cuando la correlación es mayor que 0, pero iguales al 7% cuando la correlación es 0. Muy extraño.
for simulation in range(simulations):
runs = correlated_returns(1, returns, covariances, date_index, frequency_scale)
return_history = runs['Run 0']
index_returns = return_history.mul(constituent_weights).sum(axis='columns') \
.div(constituent_weights.sum(axis='columns'))
annualized_return = (1 + index_returns[1:]).prod() ** (1 / simulation_years) - 1
¿Estoy usando mal multivariante_normal ¿de alguna manera?
0 votos
Gracias a un par de personas en este sitio que me ayudó a darse cuenta de que debo tener un error de código en lugar de descubrir nuevas finanzas :)