2012-02-17 9 views
3

OK。私はこのサイトのまったく新しい "Hello All"です!まあ、私は先週難しい問題に取り組んできました。あなたが私に与えることができる助けに感謝します。Reg Zを使用したAPRの計算付録J

APRを計算する数式は数多くありますが、私は多くの数式をテストしており、クローズドエンド(消費者ローン)に対しては奇数日を適切に処理していません。政府は、彼らの真実の貸し付け行為に付録Jを出版することによって、単なる死人にこれを助けようと試みました。 ここには次のようなものがあります:https://www.fdic.gov/regulations/laws/rules/6500-3550.html

あなたが勇気があれば、ローンの奇妙な日を含め、APRのために解決する数式を見ることができます。奇数 - 日は、定期的な支払いで実際にはカバーされていないが、利息は依然として請求されているローンの開始時の日数です。たとえば、2012年1月20日に1,000,000円のローンを受け取り、最初の支払いは03/01/2012です。 2012年1月20日から2012年1月30日までの奇妙な日が10日あります。すべての月は計算のために30日です。

私が望んでいるのは、Calculusの重要な背景を持つ人で、付録Jを半分ほど見つけ出す式を解釈できる人です。これらの式を解くために使用しているActuarialメソッドを解釈します。私は反復プロセスを理解しています。私はまずニュートン・ラフソン法を使ってこの問題を解決しようとしましたが、APRの私の公式は奇数日を考慮していませんでした。奇妙な日はないが、奇妙な日に苦しんでいたことはありませんでした。

この文書を読むことは非常に困難です。私はいくつかの進歩を遂げましたが、彼らがどうやってやっているのか分かりません。彼らはまるで魔法のようにいくつかのものを導入するようです。

お寄せいただきありがとうございます。 :)

答えて

5

申し訳ありませんが、あなたはドキュメントを読むのが少し難しいと言っていませんでした。実装は実際にはそれほど悪くはありません。私は繰り返し様々な単純化されたフォーラムを使用しようとして失敗し、最終的には一般的な式を使ってそれを得ました(8)。技術的にはこれは単純化です。実際の一般的な数式は、他の引数には長さがperiodの配列をとり、そのインデックスをループ内で使用します。このメソッドを使用して、反復ステップのA 'とA' 'を取得します。奇数日は(1.0 + fractions*rate)で処理され、文書には1 + f iと表示されます。レートは、期間当たりのレートであり、全体的な4月ではありません。

public double generalEquation(int period, double payment, double initialPeriods, double fractions, double rate) 
{ 
    double retval = 0; 
    for (int x = 0; x < period; x++) 
     retval += payment/((1.0 + fractions*rate)*Math.pow(1+rate,initialPeriods + x)); 
    return retval; 
} 

反復は、例題(9)と同じように動作します。原則として、私がここで行ったように、金融計算のための二重の使用がBADであるが、私はSOの例ではなく、生産のコードを書いていることを

/** 
* 
* @param amount The initial amount A 
* @param payment The periodic payment P 
* @param payments The total number of payments n 
* @param ppy The number of payment periods per year 
* @param APRGuess The guess to start estimating from, 10% is 0.1, not 0.001 
* @param partial Odd days, as a fraction of a pay period. 10 days of a month is 0.33333... 
* @param full Full pay periods before the first payment. Usually 1. 
* @return The calculated APR 
*/ 
public double findAPRGEQ(double amount, double payment, int payments, double ppy, double APRGuess, double partial, double full)  
{ 
    double result = APRGuess; 
    double tempguess = APRGuess;  

    do 
    { 
     result = tempguess; 
     //Step 1 
     double i = tempguess/(100*ppy); 
     double A1 = generalEquation(payments, payment, full, partial, i); 
     //Step 2 
     double i2 = (tempguess + 0.1)/(100*ppy); 
     double A2 = generalEquation(payments, payment, full, partial, i2); 
     //Step 3 
     tempguess = tempguess + 0.1*(amount - A1)/(A2 - A1); 
     System.out.println(tempguess); 
    } while (Math.abs(result*10000 - tempguess*10000) > 1); 
    return result; 
} 

注意。また、それは.netの代わりにjavaですが、アルゴリズムに役立つはずです。

0

これは古いスレッドです。私はこのコードをPHP(またはJavaScript)に翻訳する時間を無駄にしないように助けたいと思います。これは非常に不正確な結果をもたらし、実際にJava -

<?php 
function generalEquation($period, $payment, $initialPeriods, $fractions, $rate){ 
    $retval = 0; 
    for ($x = 0; $x < $period; $x++) 
     $retval += $payment/((1.0 + $fractions*$rate)*pow(1+$rate,$initialPeriods + $x)); 
    return $retval; 
} 

/** 
* 
* @param amount The initial amount A 
* @param payment The periodic payment P 
* @param payments The total number of payments n 
* @param ppy The number of payment periods per year 
* @param APRGuess The guess to start estimating from, 10% is 0.1, not 0.001 
* @param partial Odd days, as a fraction of a pay period. 10 days of a month is 0.33333... 
* @param full Full pay periods before the first payment. Usually 1. 
* @return The calculated APR 
*/ 
function findAPR($amount, $payment, $payments, $ppy, $APRGuess, $partial, $full)  
{ 
    $result = $APRGuess; 
    $tempguess = $APRGuess;  

    do 
    { 
     $result = $tempguess; 
     //Step 1 
     $i = $tempguess/(100*$ppy); 
     $A1 = generalEquation($payments, $payment, $full, $partial, $i); 
     //Step 2 
     $i2 = ($tempguess + 0.1)/(100*$ppy); 
     $A2 = generalEquation($payments, $payment, $full, $partial, $i2); 
     //Step 3 
     $tempguess = $tempguess + 0.1*($amount - $A1)/($A2 - $A1); 
    } while (abs($result*10000 - $tempguess*10000) > 1); 
    return $result; 
} 
// these figures should calculate to 12.5 apr (see below).. 
$apr = findAPR(10000,389.84,(30*389.84),12,.11,0,1); 
echo "APR: $apr" . "%"; 
?> 

4月:12.5000パーセント 合計財務費用:$ 1,695.32 融資額:$ 10,000.00 総支払:$ 11,695.32 合計ローン:$ 10,000.00 月払い:$ 389.84 利息合計:$ 1,695。32

+0

私は、Java(私は思う)が非常に簡単にC#に移植され、aprwinにマッチした(監査人が使用する) –

0

ここにPython(3.4)の翻訳があります。そして、私の申請は日付を入力し、完全な支払い期間と部分的な支払い期間ではないので、それらを計算する方法を投げました。 OCCのAPRWINを書いた人の一人がdocumentを参照しました。これを再翻訳する必要がある場合は、他の人に読んでもらうようお勧めします。

私のテストは、Reg Zの例からまっすぐです。私はまだAPRWINとのさらなるテストを行っていません。私が対処する必要がない(ケースのためにコード化していない)辺のケースは、2回の分割払いしかなく、最初は不規則な期間です。上のドキュメントがアプリの潜在的なユースケースであるかどうかを確認してください。私はまた、私のアプリは毎月と四半期ごとに必要なので、ほとんどの支払いスケジュールを完全にテストしていません。残りの部分は、Reg Zの例を使用するためのものです。

# loan_amt: initial amount of A 
# payment_amt: periodic payment P 
# num_of_pay: total number of payment P 
# ppy: number of payment periods per year 
# apr_guess: guess to start estimating from. Default = .05, or 5% 
# odd_days: odd days, meaning the fraction of a pay period for the first 
    # installment. If the pay period is monthly & the first installment is 
    # due after 45 days, the odd_days are 15/30. 
# full: full pay periods before the first payment. Usually 1 
# advance: date the finance contract is supposed to be funded 
# first_payment_due: first due date on the finance contract 

import datetime 
from dateutil.relativedelta import relativedelta 

def generalEquation(period, payment_amt, full, odd_days, rate): 
    retval = 0 
    for x in range(period): 
     retval += payment_amt/((1.0 + odd_days * rate) * ((1 + rate) ** (
      x + full))) 
    return retval 

def _dt_to_int(dt): 
    """A convenience function to change datetime objects into a day count, 
     represented by an integer""" 
    date_to_int = datetime.timedelta(days=1) 
    _int = int(dt/date_to_int) 
    return _int 

def dayVarConversions(advance, first_payment_due, ppy): 
    """Takes two datetime.date objects plus the ppy and returns the remainder 
    of a pay period for the first installment of an irregular first payment 
    period (odd_days) and the number of full pay periods before the first 
    installment (full).""" 

    if isinstance(advance, datetime.date) and isinstance(first_payment_due, 
     datetime.date): 
     advance_to_first = -relativedelta(advance, first_payment_due) 
      # returns a relativedelta object. 

      ## Appendix J requires calculating odd_days by counting BACKWARDS 
      ## from the later date, first subtracting full unit-periods, then 
      ## taking the remainder as odd_days. relativedelta lets you 
      ## calculate this easily. 

      # advance_date = datetime.date(2015, 2, 27) 
      # first_pay_date = datetime.date(2015, 4, 1) 
      # incorrect = relativedelta(first_pay_date, advance_date) 
      # correct = -relativedelta(advance_date, first_pay_date) 
      # print("See the difference between ", correct, " and ", incorrect, "?") 

     if ppy == 12: 
      # If the payment schedule is monthly 
      full = advance_to_first.months + (advance_to_first.years * 12) 
      odd_days = advance_to_first.days/30 
      if odd_days == 1: 
       odd_days = 0 
       full += 1 
       # Appendix J (b)(5)(ii) requires the use of 30 in the 
       # denominator even if a month has 31 days, so Jan 1 to Jan 31 
       # counts as a full month without any odd days. 
      return full, odd_days 

     elif ppy == 4: 
      # If the payment schedule is quarterly 
      full = (advance_to_first.months // 3) + (advance_to_first.years * 4) 
      odd_days = ((advance_to_first.months % 3) * 30 + advance_to_first. \ 
       days)/90 
      if odd_days == 1: 
       odd_days = 0 
       full += 1 
       # Same as above. Sometimes odd_days would be 90/91, but not under 
       # Reg Z. 
      return full, odd_days 

     elif ppy == 2: 
      # Semiannual payments 
      full = (advance_to_first.months // 6) + (advance_to_first.years * 2) 
      odd_days = ((advance_to_first.months % 6) * 30 + advance_to_first. \ 
       days)/180 
      if odd_days == 1: 
       odd_days = 0 
       full += 1 
      return full, odd_days 

     elif ppy == 24: 
      # Semimonthly payments 
      full = (advance_to_first.months * 2) + (advance_to_first.years * \ 
       24) + (advance_to_first.days // 15) 
      odd_days = ((advance_to_first.days % 15)/15) 
      if odd_days == 1: 
       odd_days = 0 
       full += 1 
      return full, odd_days 

     elif ppy == 52: 
      # If the payment schedule is weekly, then things get real 
      convert_to_days = first_payment_due - advance 
       # Making a timedelta object 
      days_per_week = datetime.timedelta(days=7) 
       # A timedelta object equal to 1 week 
      if advance_to_first.years == 0: 
       full, odd_days = divmod(convert_to_days, days_per_week) 
        # Divide, save the remainder 
       odd_days = _dt_to_int(odd_days)/7 
        # Convert odd_days from a timedelta object to an int 
       return full, odd_days 
      elif advance_to_first.years != 0 and advance_to_first.months == 0 \ 
       and advance_to_first.days == 0: 
       # An exact year is an edge case. By convention, we consider 
       # this 52 weeks, not 52 weeks & 1 day (2 if a leap year) 
       full = 52 * advance_to_first.years 
       odd_days = 0 
       return full, odd_days     
      else: 
       # For >1 year, there need to be exactly 52 weeks per year, 
       # meaning 364 day years. The 365th day is a freebie. 
       year_remainder = convert_to_days - datetime.timedelta(days=(
        365 * advance_to_first.years)) 
       full, odd_days = divmod(year_remainder, days_per_week) 
       full += 52 * advance_to_first.years 
        # Sum weeks from this year, weeks from past years 
       odd_days = _dt_to_int(odd_days)/7 
        # Convert odd_days from a timedelta object to an int 
       return full, odd_days 

     else: 
      print("What ppy was that?") 
       ### Raise an error appropriate to your application 

    else: 
     print("'advance' and 'first_payment_due' should both be datetime.date objects") 

def regulationZ_APR(loan_amt, payment_amt, num_of_pay, ppy, advance, 
    first_payment_due, apr_guess=.05): 
    """Returns the calculated APR using Regulation Z/Truth In Lending Appendix 
    J's calculation method""" 
    result = apr_guess 
    tempguess = apr_guess + .1 
    full, odd_days = dayVarConversions(advance, first_payment_due, ppy) 

    while abs(result - tempguess) > .00001: 
     result = tempguess 
      # Step 1 
     rate = tempguess/(100 * ppy) 
     A1 = generalEquation(num_of_pay, payment_amt, full, odd_days, rate) 
      # Step 2 
     rate2 = (tempguess + 0.1)/(100 * ppy) 
     A2 = generalEquation(num_of_pay, payment_amt, full, odd_days, rate2) 
      # Step 3 
     tempguess = tempguess + 0.1 * (loan_amt - A1)/(A2 - A1) 

    return result 


import unittest 
class RegZTest(unittest.TestCase): 
    def test_regular_first_period(self): 
     testVar = round(regulationZ_APR(5000, 230, 24, 12, 
      datetime.date(1978, 1, 10), datetime.date(1978, 2, 10)), 2) 
     self.assertEqual(testVar, 9.69) 

    def test_long_first_payment(self): 
     testVar = round(regulationZ_APR(6000, 200, 36, 12, 
      datetime.date(1978, 2, 10), datetime.date(1978, 4, 1)), 2) 
     self.assertEqual(testVar, 11.82) 

    def test_semimonthly_payment_short_first_period(self): 
     testVar = round(regulationZ_APR(5000, 219.17, 24, 24, 
      datetime.date(1978, 2, 23), datetime.date(1978, 3, 1)), 2) 
     self.assertEqual(testVar, 10.34) 

    def test_semimonthly_payment_short_first_period2(self): 
     testVar = round(regulationZ_APR(5000, 219.17, 24, 24, 
      datetime.date(1978, 2, 23), datetime.date(1978, 3, 1), apr_guess= 
      10.34), 2) 
     self.assertEqual(testVar, 10.34) 

    def test_quarterly_payment_long_first_period(self): 
     testVar = round(regulationZ_APR(10000, 385, 40, 4, 
      datetime.date(1978, 5, 23), datetime.date(1978, 10, 1), apr_guess= 
      .35), 2) 
     self.assertEqual(testVar, 8.97) 

    def test_weekly_payment_long_first_period(self): 
     testVar = round(regulationZ_APR(500, 17.6, 30, 52, 
      datetime.date(1978, 3, 20), datetime.date(1978, 4, 21), apr_guess= 
      .1), 2) 
     self.assertEqual(testVar, 14.96) 

class dayVarConversionsTest(unittest.TestCase):  
    def test_regular_month(self): 
     full, odd_days = dayVarConversions(datetime.date(1978, 1, 10), datetime.date(
      1978, 2, 10), 12) 
     self.assertEqual(full, 1) 
     self.assertEqual(odd_days, 0) 

    def test_long_month(self): 
     full, odd_days = dayVarConversions(datetime.date(1978, 2, 10), datetime.date(
      1978, 4, 1), 12) 
     self.assertEqual(full, 1) 
     self.assertEqual(odd_days, 19/30) 

    def test_semimonthly_short(self): 
     full, odd_days = dayVarConversions(datetime.date(1978, 2, 23), datetime.date(
      1978, 3, 1), 24) 
     self.assertEqual(full, 0) 
     self.assertEqual(odd_days, 6/15) 

    def test_quarterly_long(self): 
     full, odd_days = dayVarConversions(datetime.date(1978, 5, 23), datetime.date(
      1978, 10, 1), 4) 
     self.assertEqual(full, 1) 
     self.assertEqual(odd_days, 39/90) 

    def test_weekly_long(self): 
     full, odd_days = dayVarConversions(datetime.date(1978, 3, 20), datetime.date(
      1978, 4, 21), 52) 
     self.assertEqual(full, 4) 
     self.assertEqual(odd_days, 4/7) 
関連する問題