Estoy creando una aplicación financiera en la que tengo que resolver una tasa (rendimiento de bonos) que descuenta los flujos de caja a un valor presente. Estamos resolviendo para la tasa.
¿Cuál sería la mejor manera de hacer esto en Javascript? Lo que tengo funciona, pero creo que se puede optimizar, ya que actualmente puede tardar entre 60 y 70 ms, incluso con un parámetro sólido de "mejor suposición".
Además, ¿existe una forma algorítmica de determinar el incremento de iteración y el error permitido de modo que nunca haya un momento en que el incremento de iteración sea demasiado grande para poder encontrar el error permitido?
Todas las sugerencias muy bienvenidas.
Muchas gracias
const solveDcfYield = ( workoutCashflows, target, bestGuess=0.00, iteratingIncrement=0.000001, allowableError=0.0001, maxIterations=1000000) => { /** * @param {array} workoutCashflows Array of cashflows for specific settle and exchange. * @param {float} target Value for which to solve toward. * @param {float} bestGuess Best Guess to optimise algorithm solve time. As percentage eg 5.00. * @param {float} iteratingIncrement Value to increment solver each iteration. * @param {float} allowableError Minimum distance from target to solve, unless max iterations hit. * @param {int} maxIterations Maximum number of iterations to un in the solver * * @return {float} r Rate/yield that discounts cashflows coto within allowableError of target */ let iteratingDifference = allowableError + 10; let r = bestGuess/100; let iterations = 0; let startTime = new Date().getTime(); while ((( iteratingDifference > allowableError) || (iteratingDifference < -allowableError)) && (iterations <= maxIterations)) { iteratingDifference = target - sumAndDiscountCashFlows(workoutCashflows, r); r = (iteratingDifference > 0) ? (r - iteratingIncrement) : (r + iteratingIncrement); iteratingDifference = parseFloat(iteratingDifference.toFixed(8)); iterations = iterations + 1; if (iterations === (maxIterations - 1)){ console.log("maximum iterations hit..."); } }; let endTime = new Date().getTime(); let time = endTime - startTime console.log("Solver Algorithm Execution Time: ", time); return r; };
Una manera eficiente de calcular el rendimiento al vencimiento de un bono 1 es utilizar el método de Newton , que requiere el cálculo de derivadas, que derivo a continuación.
Puedes expresar tu problema de la siguiente manera.
Dejar
α = 1/(1+i)
Después
pags = α norte f + c(1+α -0.5 )Σ j=1.. n α j
Tenga en cuenta que α -0.5 es un ajuste que aumenta ligeramente el valor de los cupones de mitad de año para que puedan descontarse del final del mismo año para proporcionar un valor presente equivalente. Esto se sigue de la siguiente identidad.
α(cα -0.5 ) = cα 0.5
Como
Σ j=1.. n α j
se ve que es la suma de una serie geométrica podemos escribir:
p = fαn + (1+α -0.5 )cα( αn -1)/(1-α)
lo que equivale a lo siguiente:
p = (f(1-α) + (1+α -0.5 )αc)α n - (1+α -0.5 )αc)(1-α) -1
Ahora defina las siguientes funciones.
g1(α) = (1+α -0.5 )ac
g2(α) = (f(1-α)+g1(α))
g3(α) = α norte
g4(α) = (1-α) -1
g5(α) = g2(α)g3(α)-1
h(α) = g1(α)g5(α)g4(α)
Deseamos encontrar α + para el cual
h(a + ) = pag
Como α + = 1/(1+i), el rendimiento al vencimiento es por lo tanto igual a 1/α + -1.
La derivada de h
relativa a α
es la siguiente:
h'(α) = g1'(α)g5(α)g4(α) + g1(α)g5'(α)g4(α) + g1(α)g5(α)g4'(α)
dónde
g1'(α) = (-0.5α -1.5 )ac + (1+α -0.5 )c
g2'(α) = -f+g1'(α)
g3'(α) = nα n-1
g4'(α) = -1/(1-α) 2
g5'(α) = g2'(α)g3(α) + g2(α)g3'(α)
Podríamos comenzar estableciendo α igual a algún rendimiento promedio α 0 . Luego estime un nuevo valor de α utilizando la aproximación de línea recta (es decir, el método de Newton):
h(α 0 ) + (α 0 +d)*h'(α 0 ) = p
y resolviendo para d:
d = (ph(α 0 ))/h'(α 0 ) - α 0
Por lo tanto, la nueva estimación de α es α + d. A continuación, calcule
d = (ph(α))/h'(α) - α
actualice α y continúe de esta manera hasta que el cambio en α sea lo suficientemente pequeño. Esto debería converger rápidamente, ciertamente más rápido que los métodos que no usan derivados.
1. El rendimiento al vencimiento de un bono es la tasa de descuento anual que hace que el precio de compra del bono sea igual a la suma de los valores presentes de los pagos de cupones (dos por año) más el valor presente del pago del valor nominal del bono en el Fecha de vencimiento.