ref #65: new formula functions YIELDDISC and YIELDMAT
This commit is contained in:
parent
71684d966a
commit
154effdf82
113
calc.go
113
calc.go
|
@ -554,6 +554,8 @@ type formulaFuncs struct {
|
|||
// XOR
|
||||
// YEAR
|
||||
// YEARFRAC
|
||||
// YIELDDISC
|
||||
// YIELDMAT
|
||||
// Z.TEST
|
||||
// ZTEST
|
||||
//
|
||||
|
@ -9705,3 +9707,114 @@ func (fn *formulaFuncs) SYD(argsList *list.List) formulaArg {
|
|||
}
|
||||
return newNumberFormulaArg(((cost.Number - salvage.Number) * (life.Number - per.Number + 1) * 2) / (life.Number * (life.Number + 1)))
|
||||
}
|
||||
|
||||
// YIELDDISC function calculates the annual yield of a discounted security.
|
||||
// The syntax of the function is:
|
||||
//
|
||||
// YIELDDISC(settlement,maturity,pr,redemption,[basis])
|
||||
//
|
||||
func (fn *formulaFuncs) YIELDDISC(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 4 && argsList.Len() != 5 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "YIELDDISC requires 4 or 5 arguments")
|
||||
}
|
||||
args := list.New().Init()
|
||||
args.PushBack(argsList.Front().Value.(formulaArg))
|
||||
settlement := fn.DATEVALUE(args)
|
||||
if settlement.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
args.Init()
|
||||
args.PushBack(argsList.Front().Next().Value.(formulaArg))
|
||||
maturity := fn.DATEVALUE(args)
|
||||
if maturity.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
pr := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if pr.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
if pr.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, "YIELDDISC requires pr > 0")
|
||||
}
|
||||
redemption := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if redemption.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
if redemption.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, "YIELDDISC requires redemption > 0")
|
||||
}
|
||||
basis := newNumberFormulaArg(0)
|
||||
if argsList.Len() == 5 {
|
||||
if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
}
|
||||
frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
|
||||
if frac.Type != ArgNumber {
|
||||
return frac
|
||||
}
|
||||
return newNumberFormulaArg((redemption.Number/pr.Number - 1) / frac.Number)
|
||||
}
|
||||
|
||||
// YIELDMAT function calculates the annual yield of a security that pays
|
||||
// interest at maturity. The syntax of the function is:
|
||||
//
|
||||
// YIELDMAT(settlement,maturity,issue,rate,pr,[basis])
|
||||
//
|
||||
func (fn *formulaFuncs) YIELDMAT(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 5 && argsList.Len() != 6 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "YIELDMAT requires 5 or 6 arguments")
|
||||
}
|
||||
args := list.New().Init()
|
||||
args.PushBack(argsList.Front().Value.(formulaArg))
|
||||
settlement := fn.DATEVALUE(args)
|
||||
if settlement.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
args.Init()
|
||||
args.PushBack(argsList.Front().Next().Value.(formulaArg))
|
||||
maturity := fn.DATEVALUE(args)
|
||||
if maturity.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
args.Init()
|
||||
args.PushBack(argsList.Front().Next().Next().Value.(formulaArg))
|
||||
issue := fn.DATEVALUE(args)
|
||||
if issue.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
|
||||
}
|
||||
if issue.Number >= settlement.Number {
|
||||
return newErrorFormulaArg(formulaErrorNUM, "YIELDMAT requires settlement > issue")
|
||||
}
|
||||
rate := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if rate.Type != ArgNumber {
|
||||
return rate
|
||||
}
|
||||
if rate.Number < 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, "YIELDMAT requires rate >= 0")
|
||||
}
|
||||
pr := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||
if pr.Type != ArgNumber {
|
||||
return pr
|
||||
}
|
||||
if pr.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, "YIELDMAT requires pr > 0")
|
||||
}
|
||||
basis := newNumberFormulaArg(0)
|
||||
if argsList.Len() == 6 {
|
||||
if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
}
|
||||
dim := yearFrac(issue.Number, maturity.Number, int(basis.Number))
|
||||
if dim.Type != ArgNumber {
|
||||
return dim
|
||||
}
|
||||
dis := yearFrac(issue.Number, settlement.Number, int(basis.Number))
|
||||
dsm := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
|
||||
result := 1 + dim.Number*rate.Number
|
||||
result /= pr.Number/100 + dis.Number*rate.Number
|
||||
result--
|
||||
result /= dsm.Number
|
||||
return newNumberFormulaArg(result)
|
||||
}
|
||||
|
|
28
calc_test.go
28
calc_test.go
|
@ -1354,6 +1354,12 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// SYD
|
||||
"=SYD(10000,1000,5,1)": "3000",
|
||||
"=SYD(10000,1000,5,2)": "2400",
|
||||
// YIELDDISC
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100)": "0.0622012325059031",
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100,0)": "0.0622012325059031",
|
||||
// YIELDMAT
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5.5%,101)": "0.0419422478838651",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5.5%,101,0)": "0.0419422478838651",
|
||||
}
|
||||
for formula, expected := range mathCalc {
|
||||
f := prepareCalcData(cellData)
|
||||
|
@ -2615,6 +2621,28 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=SYD(10000,1000,0,1)": "SYD requires life argument to be > 0",
|
||||
"=SYD(10000,1000,5,0)": "SYD requires per argument to be > 0",
|
||||
"=SYD(10000,1000,1,5)": "#NUM!",
|
||||
// YIELDDISC
|
||||
"=YIELDDISC()": "YIELDDISC requires 4 or 5 arguments",
|
||||
"=YIELDDISC(\"\",\"06/30/2017\",97,100,0)": "#VALUE!",
|
||||
"=YIELDDISC(\"01/01/2017\",\"\",97,100,0)": "#VALUE!",
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",\"\",100,0)": "#VALUE!",
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,\"\",0)": "#VALUE!",
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100,\"\")": "#NUM!",
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",0,100)": "YIELDDISC requires pr > 0",
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,0)": "YIELDDISC requires redemption > 0",
|
||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100,5)": "invalid basis",
|
||||
// YIELDMAT
|
||||
"=YIELDMAT()": "YIELDMAT requires 5 or 6 arguments",
|
||||
"=YIELDMAT(\"\",\"06/30/2018\",\"06/01/2014\",5.5%,101,0)": "#VALUE!",
|
||||
"=YIELDMAT(\"01/01/2017\",\"\",\"06/01/2014\",5.5%,101,0)": "#VALUE!",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"\",5.5%,101,0)": "#VALUE!",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",\"\",101,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5,\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5,5.5%,\"\")": "#NUM!",
|
||||
"=YIELDMAT(\"06/01/2014\",\"06/30/2018\",\"01/01/2017\",5.5%,101,0)": "YIELDMAT requires settlement > issue",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",-1,101,0)": "YIELDMAT requires rate >= 0",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",1,0,0)": "YIELDMAT requires pr > 0",
|
||||
"=YIELDMAT(\"01/01/2017\",\"06/30/2018\",\"06/01/2014\",5.5%,101,5)": "invalid basis",
|
||||
}
|
||||
for formula, expected := range mathCalcError {
|
||||
f := prepareCalcData(cellData)
|
||||
|
|
Loading…
Reference in New Issue