forked from p30928647/excelize
ref #65: new formula function YIELD
This commit is contained in:
parent
f26df480e5
commit
49c9ea40d7
108
calc.go
108
calc.go
|
@ -604,6 +604,7 @@ type formulaFuncs struct {
|
||||||
// XOR
|
// XOR
|
||||||
// YEAR
|
// YEAR
|
||||||
// YEARFRAC
|
// YEARFRAC
|
||||||
|
// YIELD
|
||||||
// YIELDDISC
|
// YIELDDISC
|
||||||
// YIELDMAT
|
// YIELDMAT
|
||||||
// Z.TEST
|
// Z.TEST
|
||||||
|
@ -1492,7 +1493,7 @@ func (fn *formulaFuncs) BESSELJ(argsList *list.List) formulaArg {
|
||||||
return fn.bassel(argsList, false)
|
return fn.bassel(argsList, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bassel is an implementation of the formula function BESSELI and BESSELJ.
|
// bassel is an implementation of the formula functions BESSELI and BESSELJ.
|
||||||
func (fn *formulaFuncs) bassel(argsList *list.List, modfied bool) formulaArg {
|
func (fn *formulaFuncs) bassel(argsList *list.List, modfied bool) formulaArg {
|
||||||
x, n := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber()
|
x, n := argsList.Front().Value.(formulaArg).ToNumber(), argsList.Back().Value.(formulaArg).ToNumber()
|
||||||
if x.Type != ArgNumber {
|
if x.Type != ArgNumber {
|
||||||
|
@ -1826,7 +1827,7 @@ func (fn *formulaFuncs) BITXOR(argsList *list.List) formulaArg {
|
||||||
return fn.bitwise("BITXOR", argsList)
|
return fn.bitwise("BITXOR", argsList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bitwise is an implementation of the formula function BITAND, BITLSHIFT,
|
// bitwise is an implementation of the formula functions BITAND, BITLSHIFT,
|
||||||
// BITOR, BITRSHIFT and BITXOR.
|
// BITOR, BITRSHIFT and BITXOR.
|
||||||
func (fn *formulaFuncs) bitwise(name string, argsList *list.List) formulaArg {
|
func (fn *formulaFuncs) bitwise(name string, argsList *list.List) formulaArg {
|
||||||
if argsList.Len() != 2 {
|
if argsList.Len() != 2 {
|
||||||
|
@ -1937,7 +1938,7 @@ func (fn *formulaFuncs) DEC2OCT(argsList *list.List) formulaArg {
|
||||||
return fn.dec2x("DEC2OCT", argsList)
|
return fn.dec2x("DEC2OCT", argsList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dec2x is an implementation of the formula function DEC2BIN, DEC2HEX and
|
// dec2x is an implementation of the formula functions DEC2BIN, DEC2HEX and
|
||||||
// DEC2OCT.
|
// DEC2OCT.
|
||||||
func (fn *formulaFuncs) dec2x(name string, argsList *list.List) formulaArg {
|
func (fn *formulaFuncs) dec2x(name string, argsList *list.List) formulaArg {
|
||||||
if argsList.Len() < 1 {
|
if argsList.Len() < 1 {
|
||||||
|
@ -4586,7 +4587,7 @@ func calcStdev(stdeva bool, result, count float64, mean, token formulaArg) (floa
|
||||||
return result, count
|
return result, count
|
||||||
}
|
}
|
||||||
|
|
||||||
// stdev is an implementation of the formula function STDEV and STDEVA.
|
// stdev is an implementation of the formula functions STDEV and STDEVA.
|
||||||
func (fn *formulaFuncs) stdev(stdeva bool, argsList *list.List) formulaArg {
|
func (fn *formulaFuncs) stdev(stdeva bool, argsList *list.List) formulaArg {
|
||||||
count, result := -1.0, -1.0
|
count, result := -1.0, -1.0
|
||||||
var mean formulaArg
|
var mean formulaArg
|
||||||
|
@ -4947,7 +4948,7 @@ func (fn *formulaFuncs) CHIDIST(argsList *list.List) formulaArg {
|
||||||
return newNumberFormulaArg(1 - (incompleteGamma(degress.Number/2, x.Number/2) / math.Gamma(degress.Number/2)))
|
return newNumberFormulaArg(1 - (incompleteGamma(degress.Number/2, x.Number/2) / math.Gamma(degress.Number/2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// confidence is an implementation of the formula function CONFIDENCE and
|
// confidence is an implementation of the formula functions CONFIDENCE and
|
||||||
// CONFIDENCE.NORM.
|
// CONFIDENCE.NORM.
|
||||||
func (fn *formulaFuncs) confidence(name string, argsList *list.List) formulaArg {
|
func (fn *formulaFuncs) confidence(name string, argsList *list.List) formulaArg {
|
||||||
if argsList.Len() != 3 {
|
if argsList.Len() != 3 {
|
||||||
|
@ -10735,13 +10736,22 @@ func (fn *formulaFuncs) price(settlement, maturity, rate, yld, redemption, frequ
|
||||||
dsc := fn.COUPDAYSNC(argsList).Number / e.Number
|
dsc := fn.COUPDAYSNC(argsList).Number / e.Number
|
||||||
n := fn.COUPNUM(argsList)
|
n := fn.COUPNUM(argsList)
|
||||||
a := fn.COUPDAYBS(argsList)
|
a := fn.COUPDAYBS(argsList)
|
||||||
ret := redemption.Number / math.Pow(1+yld.Number/frequency.Number, n.Number-1+dsc)
|
ret := 0.0
|
||||||
|
if n.Number > 1 {
|
||||||
|
ret = redemption.Number / math.Pow(1+yld.Number/frequency.Number, n.Number-1+dsc)
|
||||||
ret -= 100 * rate.Number / frequency.Number * a.Number / e.Number
|
ret -= 100 * rate.Number / frequency.Number * a.Number / e.Number
|
||||||
t1 := 100 * rate.Number / frequency.Number
|
t1 := 100 * rate.Number / frequency.Number
|
||||||
t2 := 1 + yld.Number/frequency.Number
|
t2 := 1 + yld.Number/frequency.Number
|
||||||
for k := 0.0; k < n.Number; k++ {
|
for k := 0.0; k < n.Number; k++ {
|
||||||
ret += t1 / math.Pow(t2, k+dsc)
|
ret += t1 / math.Pow(t2, k+dsc)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
dsc = e.Number - a.Number
|
||||||
|
t1 := 100*(rate.Number/frequency.Number) + redemption.Number
|
||||||
|
t2 := (yld.Number/frequency.Number)*(dsc/e.Number) + 1
|
||||||
|
t3 := 100 * (rate.Number / frequency.Number) * (a.Number / e.Number)
|
||||||
|
ret = t1/t2 - t3
|
||||||
|
}
|
||||||
return newNumberFormulaArg(ret)
|
return newNumberFormulaArg(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11496,6 +11506,92 @@ func (fn *formulaFuncs) XNPV(argsList *list.List) formulaArg {
|
||||||
return newNumberFormulaArg(xnpv)
|
return newNumberFormulaArg(xnpv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// yield is an implementation of the formula function YIELD.
|
||||||
|
func (fn *formulaFuncs) yield(settlement, maturity, rate, pr, redemption, frequency, basis formulaArg) formulaArg {
|
||||||
|
priceN, yield1, yield2 := newNumberFormulaArg(0), newNumberFormulaArg(0), newNumberFormulaArg(1)
|
||||||
|
price1 := fn.price(settlement, maturity, rate, yield1, redemption, frequency, basis)
|
||||||
|
if price1.Type != ArgNumber {
|
||||||
|
return price1
|
||||||
|
}
|
||||||
|
price2 := fn.price(settlement, maturity, rate, yield2, redemption, frequency, basis)
|
||||||
|
yieldN := newNumberFormulaArg((yield2.Number - yield1.Number) * 0.5)
|
||||||
|
for iter := 0; iter < 100 && priceN.Number != pr.Number; iter++ {
|
||||||
|
priceN = fn.price(settlement, maturity, rate, yieldN, redemption, frequency, basis)
|
||||||
|
if pr.Number == price1.Number {
|
||||||
|
return yield1
|
||||||
|
} else if pr.Number == price2.Number {
|
||||||
|
return yield2
|
||||||
|
} else if pr.Number == priceN.Number {
|
||||||
|
return yieldN
|
||||||
|
} else if pr.Number < price2.Number {
|
||||||
|
yield2.Number *= 2.0
|
||||||
|
price2 = fn.price(settlement, maturity, rate, yield2, redemption, frequency, basis)
|
||||||
|
yieldN.Number = (yield2.Number - yield1.Number) * 0.5
|
||||||
|
} else {
|
||||||
|
if pr.Number < priceN.Number {
|
||||||
|
yield1 = yieldN
|
||||||
|
price1 = priceN
|
||||||
|
} else {
|
||||||
|
yield2 = yieldN
|
||||||
|
price2 = priceN
|
||||||
|
}
|
||||||
|
yieldN.Number = yield2.Number - (yield2.Number-yield1.Number)*((pr.Number-price2.Number)/(price1.Number-price2.Number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return yieldN
|
||||||
|
}
|
||||||
|
|
||||||
|
// YIELD function calculates the Yield of a security that pays periodic
|
||||||
|
// interest. The syntax of the function is:
|
||||||
|
//
|
||||||
|
// YIELD(settlement,maturity,rate,pr,redemption,frequency,[basis])
|
||||||
|
//
|
||||||
|
func (fn *formulaFuncs) YIELD(argsList *list.List) formulaArg {
|
||||||
|
if argsList.Len() != 6 && argsList.Len() != 7 {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, "YIELD requires 6 or 7 arguments")
|
||||||
|
}
|
||||||
|
args := fn.prepareDataValueArgs(2, argsList)
|
||||||
|
if args.Type != ArgList {
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
settlement, maturity := args.List[0], args.List[1]
|
||||||
|
rate := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
|
||||||
|
if rate.Type != ArgNumber {
|
||||||
|
return rate
|
||||||
|
}
|
||||||
|
if rate.Number < 0 {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, "PRICE requires rate >= 0")
|
||||||
|
}
|
||||||
|
pr := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||||
|
if pr.Type != ArgNumber {
|
||||||
|
return pr
|
||||||
|
}
|
||||||
|
if pr.Number <= 0 {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, "PRICE requires pr > 0")
|
||||||
|
}
|
||||||
|
redemption := argsList.Front().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||||
|
if redemption.Type != ArgNumber {
|
||||||
|
return redemption
|
||||||
|
}
|
||||||
|
if redemption.Number < 0 {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, "PRICE requires redemption >= 0")
|
||||||
|
}
|
||||||
|
frequency := argsList.Front().Next().Next().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||||
|
if frequency.Type != ArgNumber {
|
||||||
|
return frequency
|
||||||
|
}
|
||||||
|
if !validateFrequency(frequency.Number) {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||||
|
}
|
||||||
|
basis := newNumberFormulaArg(0)
|
||||||
|
if argsList.Len() == 7 {
|
||||||
|
if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fn.yield(settlement, maturity, rate, pr, redemption, frequency, basis)
|
||||||
|
}
|
||||||
|
|
||||||
// YIELDDISC function calculates the annual yield of a discounted security.
|
// YIELDDISC function calculates the annual yield of a discounted security.
|
||||||
// The syntax of the function is:
|
// The syntax of the function is:
|
||||||
//
|
//
|
||||||
|
|
22
calc_test.go
22
calc_test.go
|
@ -1508,6 +1508,7 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2)": "110.65510517844305",
|
"=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2)": "110.65510517844305",
|
||||||
"=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2,4)": "110.65510517844305",
|
"=PRICE(\"04/01/2012\",\"02/01/2020\",12%,10%,100,2,4)": "110.65510517844305",
|
||||||
"=PRICE(\"04/01/2012\",\"03/31/2020\",12%,10%,100,2)": "110.83448359321572",
|
"=PRICE(\"04/01/2012\",\"03/31/2020\",12%,10%,100,2)": "110.83448359321572",
|
||||||
|
"=PRICE(\"01/01/2010\",\"06/30/2010\",0.5,1,1,1,4)": "8.924190888476605",
|
||||||
// PPMT
|
// PPMT
|
||||||
"=PPMT(0.05/12,2,60,50000)": "-738.2918003208238",
|
"=PPMT(0.05/12,2,60,50000)": "-738.2918003208238",
|
||||||
"=PPMT(0.035/4,2,8,0,5000,1)": "-606.1094824182949",
|
"=PPMT(0.035/4,2,8,0,5000,1)": "-606.1094824182949",
|
||||||
|
@ -1552,6 +1553,12 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=VDB(24000,3000,10,0.1,1,1)": "2138.3999999999996",
|
"=VDB(24000,3000,10,0.1,1,1)": "2138.3999999999996",
|
||||||
"=VDB(24000,3000,100,50,100,1)": "10377.294418465235",
|
"=VDB(24000,3000,100,50,100,1)": "10377.294418465235",
|
||||||
"=VDB(24000,3000,100,50,100,2)": "5740.072322090805",
|
"=VDB(24000,3000,100,50,100,2)": "5740.072322090805",
|
||||||
|
// YIELD
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,4)": "0.0975631546829798",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,4,4)": "0.0976269355643988",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2010\",0.5,1,1,1,4)": "1.91285866099894",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2010\",0,1,1,1,4)": "0",
|
||||||
|
"=YIELD(\"01/01/2010\",\"01/02/2020\",100,68.15518653988686,1,1,1)": "64",
|
||||||
// YIELDDISC
|
// YIELDDISC
|
||||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100)": "0.0622012325059031",
|
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100)": "0.0622012325059031",
|
||||||
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100,0)": "0.0622012325059031",
|
"=YIELDDISC(\"01/01/2017\",\"06/30/2017\",97,100,0)": "0.0622012325059031",
|
||||||
|
@ -3124,6 +3131,21 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=VDB(10000,1000,5,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=VDB(10000,1000,5,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
"=VDB(10000,1000,5,0,1,\"\")": "#NUM!",
|
"=VDB(10000,1000,5,0,1,\"\")": "#NUM!",
|
||||||
"=VDB(10000,1000,5,0,1,0.2,\"\")": "#NUM!",
|
"=VDB(10000,1000,5,0,1,0.2,\"\")": "#NUM!",
|
||||||
|
// YIELD
|
||||||
|
"=YIELD()": "YIELD requires 6 or 7 arguments",
|
||||||
|
"=YIELD(\"\",\"06/30/2015\",10%,101,100,4)": "#VALUE!",
|
||||||
|
"=YIELD(\"01/01/2010\",\"\",10%,101,100,4)": "#VALUE!",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",\"\",101,100,4)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,\"\",100,4)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,\"\",4)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,4,\"\")": "#NUM!",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,3)": "#NUM!",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,4,5)": "invalid basis",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",-1,101,100,4)": "PRICE requires rate >= 0",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,0,100,4)": "PRICE requires pr > 0",
|
||||||
|
"=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,-1,4)": "PRICE requires redemption >= 0",
|
||||||
|
// "=YIELD(\"01/01/2010\",\"06/30/2015\",10%,101,100,4)": "PRICE requires rate >= 0",
|
||||||
// YIELDDISC
|
// YIELDDISC
|
||||||
"=YIELDDISC()": "YIELDDISC requires 4 or 5 arguments",
|
"=YIELDDISC()": "YIELDDISC requires 4 or 5 arguments",
|
||||||
"=YIELDDISC(\"\",\"06/30/2017\",97,100,0)": "#VALUE!",
|
"=YIELDDISC(\"\",\"06/30/2017\",97,100,0)": "#VALUE!",
|
||||||
|
|
8
merge.go
8
merge.go
|
@ -269,15 +269,15 @@ func (m *MergeCell) GetCellValue() string {
|
||||||
return (*m)[1]
|
return (*m)[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStartAxis returns the merge start axis.
|
// GetStartAxis returns the top left cell coordinates of merged range, for
|
||||||
// example: "C2"
|
// example: "C2".
|
||||||
func (m *MergeCell) GetStartAxis() string {
|
func (m *MergeCell) GetStartAxis() string {
|
||||||
axis := strings.Split((*m)[0], ":")
|
axis := strings.Split((*m)[0], ":")
|
||||||
return axis[0]
|
return axis[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEndAxis returns the merge end axis.
|
// GetEndAxis returns the bottom right cell coordinates of merged range, for
|
||||||
// example: "D4"
|
// example: "D4".
|
||||||
func (m *MergeCell) GetEndAxis() string {
|
func (m *MergeCell) GetEndAxis() string {
|
||||||
axis := strings.Split((*m)[0], ":")
|
axis := strings.Split((*m)[0], ":")
|
||||||
return axis[1]
|
return axis[1]
|
||||||
|
|
|
@ -2151,8 +2151,8 @@ func (f *File) NewConditionalStyle(style string) (int, error) {
|
||||||
return s.Dxfs.Count - 1, nil
|
return s.Dxfs.Count - 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultFont provides the default font name currently set in the workbook
|
// GetDefaultFont provides the default font name currently set in the
|
||||||
// Documents generated by excelize start with Calibri.
|
// workbook. The spreadsheet generated by excelize default font is Calibri.
|
||||||
func (f *File) GetDefaultFont() string {
|
func (f *File) GetDefaultFont() string {
|
||||||
font := f.readDefaultFont()
|
font := f.readDefaultFont()
|
||||||
return *font.Name.Val
|
return *font.Name.Val
|
||||||
|
|
Loading…
Reference in New Issue