2010-06-23 23 views
2

Je fais une application qui donne aux clients et offre approximative de prêt (ils sont ensuite calculés par d'autres systèmes de back-office). J'ai reçu un code du cabinet financier pour lequel nous faisons la calculatrice. Mon problème est que je ne comprends pas la partie du code qui calcule le taux annuel en pourcentage (y compris le démarrage et les frais mensuels).Calcul du taux de pourcentage annuel (besoin d'aide avec le code hérité)

Il est peut-être cette méthode qu'ils utilisent, mais je ne peux pas vraiment dire: http://www.efunda.com/math/num_rootfinding/num_rootfinding.cfm#Newton_Raphson

Le code fonctionne correctement, mais je déteste vraiment construire une application sur le code que je ne comprends pas bien et/ou confiance. La réponse ultime serait le code source qui fait la même chose, mais avec des commentaires et des noms de variables compréhensibles (je ne suis pas vraiment :-) Toutes les idées sont les bienvenues - peut-être quelqu'un a un lien vers un article qui l'explique.

(s'il vous plaît noter que je ne suis pas un calcul ou wiz financier)

[snip] 
int n = numberOfPayments; 
double a = (amount/(monthlyPayment * Math.Pow(n, 2)) - (monthlyPayment/amount)); 
double d = 0; 
if (a == 0) 
{ 
    d = 0; 
} 
else 
{ 
    for (int qq = 0; qq < 20; qq++) 
    { 
     double b = amount + (monthlyPayment/a) * (1 - (Math.Pow((1 + a), -n))); 
     double c = amount + (monthlyPayment/a) * ((n * (Math.Pow((1 + a), (-n - 1)))) - ((1 - (Math.Pow((1 + a), -n)))/a)); 
     d = a - (b/c); 
     double aa = a; 
     double dd = d; 
     a = d; 
     if (Math.Abs(aa - dd) < Math.Pow(10, -5)) { break; } 
    } 
} 
double apr = ((Math.Pow((1 + d), 12)) - 1) * 100; 
apr = Math.Round(apr * 100)/100; 
[/snip] 

Répondre

9

Le code est en effet en utilisant la méthode de Newton-Raphson bien que je ne sais pas ce qu'il est exactement calculait; vous avez peut-être copié de la mauvaise section. Si, en effet, vous voulez calculer le taux de pourcentage annuel donné le montant du prêt, le paiement mensuel et le nombre de mois alors vous avez presque complètement résolu cela, sauf que vous ne savez probablement pas quelle est la fonction cherché et c'est, c'est compréhensible, une pierre d'achoppement.

La valeur recherchée est appelée internal rate of return (IRR) pour laquelle il n'existe pas de forme fermée; vous devez le calculer à la dure ou utiliser des méthodes numériques. Le calcul du taux annuel en pourcentage est un cas particulier du TRI où tous les paiements sont égaux et le prêt court à terme. Cela signifie que l'équation est la suivante:

P est le principal/prêt, m est le paiement mensuel, i est le taux d'intérêt, N est le nombre de mois

0 = P - Sum[k=1..N](m*(1+i)^(-k)) 

Et nous devons résoudre pour i.L'équation ci-dessus est équivalente à:

P = Sum[k=1..N](m*(1+i)^(-k)) 
P = m * Sum[k=1..N]((1+i)^(-k)) // monthly payments all the same 
P/m = Sum[k=1..N]((1+i)^(-k)) 

Il y a quelques formules pour obtenir la forme fermée pour la somme sur le côté droit qui se traduisent par l'équation suivante qui concerne toutes les quantités que nous connaissons déjà (terme, prêt , et le montant du paiement mensuel) et qui est beaucoup plus traitable:

monthlyPayment = loanAmount * interestRate * ((1 + interestRate)^numberOfPayments)/(((1 + interestRate)^numberOfPayments) - 1) 

Pour réduire la saisie laisser:

  • P est le principal/prêt
  • m est récurrent montant du paiement
  • N est le nombre total de paiements

Ainsi, l'équation dont les racines, nous devons trouver est:

F(x) = P * x * ((1 + x)^N)/(((1 + x)^N) - 1) - m 

Pour utiliser la méthode de Newton-Rhapson nous avons besoin firstderivative de F par rapport à x:

F_1(x) = P * ((1 + x)^N/(-1 + (1 + x)^N) - ((N * x * (1 + x)^(-1 + 2*N))/(-1 + (1 + x)^N)^2) + (N * x * (1 + x)^(-1 + N))/(-1 + (1 + x)^N)) 

Le code suivant en Groovy fait le calcul correct:

numPay = 360 
payment = 1153.7 
amount = 165000 
double error = Math.pow(10,-5) 
double approx = 0.05/12 // let's start with a guess that the APR is 5% 
double prev_approx 

def F(x) { 
    return amount * x * Math.pow(1 + x,numPay)/(Math.pow(1 + x,numPay) - 1) - payment 
} 

def F_1(x) { 
    return amount * (Math.pow(1 + x,numPay)/(-1 + Math.pow(1 + x,numPay)) - numPay * x * Math.pow(1 + x,-1 + 2*numPay)/Math.pow(-1 + Math.pow(1 + x,numPay),2) + numPay * x * Math.pow(1 + x,-1 + numPay)/(-1 + Math.pow(1 + x,numPay))) 
} 


println "initial guess $approx" 
for (k=0;k<20;++k) { 
     prev_approx = approx 
     approx = prev_approx - F(prev_approx)/F_1(prev_approx) 
     diff = Math.abs(approx-prev_approx) 
     println "new guess $approx diff is $diff" 
     if (diff < error) break 
} 

apr = Math.round(approx * 12 * 10000)/100 // this way we get APRs like 7.5% or 6.55% 
println "APR is ${apr}% final approx $approx " 

Je ne pas utiliser le code fourni car il était un peu glauque (plus il ne fonctionne pas pour moi). Je l'ai dérivé des définitions de Newton-Rhapson et de l'équation des paiements mensuels. L'approximation converge très rapidement (10^-5 dans les 2 ou 3 itérations)

NOTE: Je ne suis pas en mesure d'obtenir ce lien pour être correctement inséré le texte dans lequel la dérivée première est d'abord mentionné: http://www.wolframalpha.com/input/?i=d/dx(+x+*+((1+%2B+x)^n)/(((1+%2B+x)^n)+-+1)+-m+)

+0

Le L'affiche ci-dessus est correcte en ce sens que le code original tente de calculer itérativement "apr", en s'arrêtant à 20 pas ou lorsque l'étape suivante produirait un changement d'au plus 10^-5. Je ne sais pas si le code d'origine est exact; c'est opaque au mieux. – Borealid

+0

Il ne peut pas être précis. J'ai essayé et ça n'a pas marché pour moi. J'ai peut-être fait une erreur en transcrivant, vrai, mais j'ai dériver ce qui est supposément le code équivalent des définitions qui ne ressemble en rien au code de la question. La première dérivée en particulier ne semble pas du tout correcte *. – Allen

+0

Impressionnant Allen - merci beaucoup! Je dois admettre que certaines des parties de votre message qui sont lourdes en mathématiques sont perdues pour moi, mais le code Groovy, en particulier, m'a fait comprendre un certain nombre de choses. Dans l'extrait que j'ai posté "monthlyPayment" est calculé exactement comme vous publiez (mais j'ai seulement posté la partie du code que j'ai eu du mal à comprendre). L'extrait que j'ai posté fonctionne, j'ai vérifié contre un certain nombre d'autres calculatrices similaires dans Excel et javascript (mais je comprends que je pourrais être trouble car il est pris un peu hors contexte) –