2013-01-20 41 views
7

作爲Formula.js項目的一部分,我試圖重新實現Excel的ACCRINT函數(在JavaScript中,但語言無關緊要)。我一直在試圖找到它應該如何工作的適當說明(特別是關於first_interest參數),但找不到任何東西。有趣的是,即使所有三個主要版本的Excel(Win,Mac,Web)似乎都認同,Excel,Google Spreadsheets,Apple Numbers,Gnumeric和OpenOffice在實現它的方式上都不一致。可以在這個blog post找到更多的上下文。如何實現Excel的ACCRINT

數十個測試用例和我目前的(有缺陷的)實現可以找到here

任何幫助將不勝感激!

UPDATE:要明確,這個問題是不是相關day count convention,我們使用實現大衛惠勒的pseudocodeYEARFRAC,這本身是由超過32萬次測試,涵蓋了所有五個選項的基礎驗證。這個問題來自first_interest參數,這個參數似乎沒有人真正理解。據我們所知,這個參數被許多其他電子表格忽略,包括OpenOffice(它在源代碼中被註釋掉了)。而這個參數真的表現得很奇怪。如果你使用Excel並且改變它的值,你會發現它會改變ACCRINT函數給出的結果,但看起來很混亂。嘗試更改一個世紀的first_interest日期,您會看到應計利息發生變化,但不會太多。我真的無法理解這一點。如果任何人都可以,我所有的耳朵...

+1

哦不!一個好問題!我怎麼忍受這個? (+1) – 2013-01-20 19:18:22

回答

0

Phil H從計量金融學發現這個.NET library,它提供了淨室實現對所有金融函數,除了兩個似乎都通過了測試(事實上201,349個測試用例)。這些包括ACCRINT。該代碼根據知識共享署名獲得許可。它是用F#編寫的,但它很清楚。 ACCRINT的代碼位於bonds.fs文件中。我們將嘗試將其移植到JavaScript,並查看我們是否獲得與Excel返回的結果相同的結果。更多關於這個......

0

這是在PHP(我認爲):從this page

/** 
    * ACCRINT 
    * 
    * Returns the discount rate for a security. 
    * 
    * @param mixed issue  The security's issue date. 
    * @param mixed firstinter The security's first interest date. 
    * @param mixed settlement The security's settlement date. 
    * @param float rate  The security's annual coupon rate. 
    * @param float par   The security's par value. 
    * @param int  basis  The type of day count to use. 
    *          0 or omitted US (NASD) 30/360 
    *          1    Actual/actual 
    *          2    Actual/360 
    *          3    Actual/365 
    *          4    European 30/360 
    * @return float 
    */ 
public static function ACCRINT($issue, $firstinter, $settlement, $rate, $par=1000, $frequency=1, $basis=0) { 
     $issue  = self::flattenSingleValue($issue); 
     $firstinter = self::flattenSingleValue($firstinter); 
     $settlement = self::flattenSingleValue($settlement); 
     $rate  = (float) self::flattenSingleValue($rate); 
     $par  = (is_null($par)) ? 1000 : (float) self::flattenSingleValue($par); 
     $frequency = (is_null($frequency)) ? 1 : (int) self::flattenSingleValue($frequency); 
     $basis  = (is_null($basis)) ? 0  : (int) self::flattenSingleValue($basis); 

     // Validate 
     if ((is_numeric($rate)) && (is_numeric($par))) { 
      if (($rate <= 0) || ($par <= 0)) { 
       return self::$_errorCodes['num']; 
      } 
      $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis); 
      if (!is_numeric($daysBetweenIssueAndSettlement)) { 
       return $daysBetweenIssueAndSettlement; 
      } 
      $daysPerYear = self::_daysPerYear(self::YEAR($issue),$basis); 
      if (!is_numeric($daysPerYear)) { 
       return $daysPerYear; 
      } 
      $daysBetweenIssueAndSettlement *= $daysPerYear; 

      return $par * $rate * ($daysBetweenIssueAndSettlement/$daysPerYear); 
     } 
     return self::$_errorCodes['value']; 
    } // function ACCRINT() 
+0

感謝您的提示! –

+0

不幸的是,這段代碼沒有考慮到頻率和首次感興趣的日期。 –