1 votos

¿Existe un algoritmo más rápido para calcular las ponderaciones de las carteras "a la deriva"? (R, Pandas/NumPy, MATLAB)

'Sup, QuantSX.

BLOT (Bottom Line On Top) : ¿Existe un algoritmo limpio y agradable para calcular rápidamente la deriva del peso de la cartera? En R, Python o MATLAB - no me importa cuál.

Detalles

Estoy en las etapas finales de la ampliación de una prueba de estrés script (en MATLAB) que he utilizado durante un tiempo, y he golpeado una pared de rendimiento en lo que debería ser una función de actualización bastante fácil.

Las tripas del script es un Monte Carlo de tamaño medio - 1000 iteraciones de 240 x n[i] para ~70 carteras, donde n[i] es el número de componentes de la cartera ith ( n[i] oscila entre ~5 y ~25). Cópula gaussiana, por lo que genera los pseudodatos superrápidos.

En el pasado, el resultado sólo se ha presentado bajo el supuesto de un equilibrio mensual, por lo que las pseudo-observaciones para la cartera en sí son sólo

$w\cdot R = \sum_i\bar{w}_i \times R_{i,t}$

donde $\bar{w}_i$ son los pesos de la cartera original y de la cartera objetivo. Y, por supuesto, eso también es súper rápido - O (mseg). De hecho, es el módulo más rápido de todo el marco de pruebas de estrés, que se completa en ~35 segundos por cartera.

Una parte de la ampliación consiste en calcular la trayectoria de la cartera bajo una serie de supuestos de reequilibrio alternativos: full-drift (es decir, sin reequilibrio, comprar y mantener); trimestral; anual; y "umbral" por clase de activos.

En las pruebas de la versión de deriva completa, está tomando 2 segundos por iteración para calcular las ponderaciones derivadas; eso parece mucho tiempo para 240 filas de datos.

Y 70 lotes de 1000 × ~2 segundos es mucho tiempo.

La ecuación de transición del peso es realmente sencilla -

$w_{i,t+1} = w_{i,t}\cdot\left(\frac{1+R_{i,t}}{1+R_{p,t}}\right)$

$w_{i,0} = \bar{w}_i$

La ponderación derivada depende de la rentabilidad de la cartera, que es la suma ponderada de las rentabilidades de los componentes en el periodo t -

$R_{p,t} = \sum_i(w_{i,t}\cdot R_{i,t}) = w'̌\cdot R$

Hasta ahora, no hay cirugía de cohetes.

Para hacer esto en MATLAB, la única forma que se me ocurrió fue inicializar un agregador, y acumular las ponderaciones recalculadas (y como subproducto, los rendimientos de la cartera "desviados").

Así que mi función se presenta a continuación (aunque mi función está correctamente sangrada)

function[outPVals, outWts, wtDiff] = DriftWts(inTable, inWts, outName) 
%% Calculates Portfolio Value and Component Weights over time if weights drift.
xT = inTable;
xP = inTable;
xT.Properties.DimensionNames{2} = 'Weights';
xT.Weights = zeros(size(xT)); %% pre-allocate weights table
xD = xT;                      %% pre-allocate weight-delta table 
tBeg = min(xT.MthYr);
xT(tBeg,:).Weights = transpose(inWts); %% initialises weights at current AA
xR = inTable(tBeg,:).Returns/100;
xP.(outName)(tBeg,:) = 100*(xR * inWts); 
xT = sortrows(xT,'MthYr','ascend');
for mmm = 2:length(xT.MthYr)
    m = xT.MthYr(mmm);
    m_l = eomdate(m - calmonths(1));
    w_l = xT(m_l,:).Weights;
    R_l = inTable(m_l,:).Returns/100;
    xR = inTable(m,:).Returns/100;
    Rp_l = w_l * transpose(R_l);
    w_0 = w_l .* (1 + R_l)/( 1 + Rp_l);
    xT(m,:).Weights = w_0;
    xD(m,:).Weights = w_0 - w_l;
    xP.(outName)(m,:) = 100*(w_0 * transpose(xR));
 end
 outWts = xT;
 outPVals = xP(:,outName);
 wtDiff = xD;
 end

Consideré una alternativa, es decir, generar cumprod(1 +$R_{i,t}$ /100) de los rendimientos de los componentes, ponderándolos por $\bar{w}_i$ en t=0, sumándolos, y luego dividiendo todo por la suma de filas.

No me parece obvio que esta alternativa sea más rápida (pero no tengo ni idea de lo que pasa bajo el capó en cumprod() Así que lo intentaré hoy)

1voto

STiLLeN Puntos 56

Bien, entonces el mecanismo "alternativo" (cumprod, peso, dividir por la suma de filas) es O(msec) y produce resultados idénticos.

  • El viejo y estúpido método: 1.705seg para una mesa de 200×9.
  • Nuevo método sexy: 0.004seg para la misma tabla.

Y sólo son 4 líneas de código.

T01 = cumprod(1+inTable/100,'reverse');
T02 = inWts' .* T01;
R01 = sum(T02, 2);
W01 = T02 ./ R01;

0 votos

Tiene sentido, estaba a punto de decir "encontrar una manera de vectorizar", pero eso es lo que hace cumprod. A menudo es la respuesta a la lentitud del código matlab.

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