Update docs for SetSheetStyle, and added 2 formula functions
ref #65: new formula functions DURATION and MDURATION fix incorrect example in SetSheetStyle docs
This commit is contained in:
parent
577a07f08c
commit
e0c6fa1beb
110
calc.go
110
calc.go
|
@ -379,6 +379,7 @@ type formulaFuncs struct {
|
||||||
// DISC
|
// DISC
|
||||||
// DOLLARDE
|
// DOLLARDE
|
||||||
// DOLLARFR
|
// DOLLARFR
|
||||||
|
// DURATION
|
||||||
// EFFECT
|
// EFFECT
|
||||||
// ENCODEURL
|
// ENCODEURL
|
||||||
// ERF
|
// ERF
|
||||||
|
@ -471,6 +472,7 @@ type formulaFuncs struct {
|
||||||
// MATCH
|
// MATCH
|
||||||
// MAX
|
// MAX
|
||||||
// MDETERM
|
// MDETERM
|
||||||
|
// MDURATION
|
||||||
// MEDIAN
|
// MEDIAN
|
||||||
// MID
|
// MID
|
||||||
// MIDB
|
// MIDB
|
||||||
|
@ -10179,6 +10181,96 @@ func (fn *formulaFuncs) dollar(name string, argsList *list.List) formulaArg {
|
||||||
return newNumberFormulaArg(math.Floor(dollar.Number) + cents)
|
return newNumberFormulaArg(math.Floor(dollar.Number) + cents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepareDurationArgs checking and prepare arguments for the formula
|
||||||
|
// functions DURATION and MDURATION.
|
||||||
|
func (fn *formulaFuncs) prepareDurationArgs(name string, argsList *list.List) formulaArg {
|
||||||
|
if argsList.Len() != 5 && argsList.Len() != 6 {
|
||||||
|
return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires 5 or 6 arguments", name))
|
||||||
|
}
|
||||||
|
args := fn.prepareDataValueArgs(2, argsList)
|
||||||
|
if args.Type != ArgList {
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
settlement, maturity := args.List[0], args.List[1]
|
||||||
|
if settlement.Number >= maturity.Number {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires maturity > settlement", name))
|
||||||
|
}
|
||||||
|
coupon := argsList.Front().Next().Next().Value.(formulaArg).ToNumber()
|
||||||
|
if coupon.Type != ArgNumber {
|
||||||
|
return coupon
|
||||||
|
}
|
||||||
|
if coupon.Number < 0 {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires coupon >= 0", name))
|
||||||
|
}
|
||||||
|
yld := argsList.Front().Next().Next().Next().Value.(formulaArg).ToNumber()
|
||||||
|
if yld.Type != ArgNumber {
|
||||||
|
return yld
|
||||||
|
}
|
||||||
|
if yld.Number < 0 {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, fmt.Sprintf("%s requires yld >= 0", name))
|
||||||
|
}
|
||||||
|
frequency := argsList.Front().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() == 6 {
|
||||||
|
if basis = argsList.Back().Value.(formulaArg).ToNumber(); basis.Type != ArgNumber {
|
||||||
|
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newListFormulaArg([]formulaArg{settlement, maturity, coupon, yld, frequency, basis})
|
||||||
|
}
|
||||||
|
|
||||||
|
// duration is an implementation of the formula function DURATION.
|
||||||
|
func (fn *formulaFuncs) duration(settlement, maturity, coupon, yld, frequency, basis formulaArg) formulaArg {
|
||||||
|
frac := yearFrac(settlement.Number, maturity.Number, int(basis.Number))
|
||||||
|
if frac.Type != ArgNumber {
|
||||||
|
return frac
|
||||||
|
}
|
||||||
|
argumments := list.New().Init()
|
||||||
|
argumments.PushBack(settlement)
|
||||||
|
argumments.PushBack(maturity)
|
||||||
|
argumments.PushBack(frequency)
|
||||||
|
argumments.PushBack(basis)
|
||||||
|
coups := fn.COUPNUM(argumments)
|
||||||
|
duration := 0.0
|
||||||
|
p := 0.0
|
||||||
|
coupon.Number *= 100 / frequency.Number
|
||||||
|
yld.Number /= frequency.Number
|
||||||
|
yld.Number++
|
||||||
|
diff := frac.Number*frequency.Number - coups.Number
|
||||||
|
for t := 1.0; t < coups.Number; t++ {
|
||||||
|
tDiff := t + diff
|
||||||
|
add := coupon.Number / math.Pow(yld.Number, tDiff)
|
||||||
|
p += add
|
||||||
|
duration += tDiff * add
|
||||||
|
}
|
||||||
|
add := (coupon.Number + 100) / math.Pow(yld.Number, coups.Number+diff)
|
||||||
|
p += add
|
||||||
|
duration += (coups.Number + diff) * add
|
||||||
|
duration /= p
|
||||||
|
duration /= frequency.Number
|
||||||
|
return newNumberFormulaArg(duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DURATION function calculates the Duration (specifically, the Macaulay
|
||||||
|
// Duration) of a security that pays periodic interest, assuming a par value
|
||||||
|
// of $100. The syntax of the function is:
|
||||||
|
//
|
||||||
|
// DURATION(settlement,maturity,coupon,yld,frequency,[basis])
|
||||||
|
//
|
||||||
|
func (fn *formulaFuncs) DURATION(argsList *list.List) formulaArg {
|
||||||
|
args := fn.prepareDurationArgs("DURATION", argsList)
|
||||||
|
if args.Type != ArgList {
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
return fn.duration(args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5])
|
||||||
|
}
|
||||||
|
|
||||||
// EFFECT function returns the effective annual interest rate for a given
|
// EFFECT function returns the effective annual interest rate for a given
|
||||||
// nominal interest rate and number of compounding periods per year. The
|
// nominal interest rate and number of compounding periods per year. The
|
||||||
// syntax of the function is:
|
// syntax of the function is:
|
||||||
|
@ -10504,6 +10596,24 @@ func (fn *formulaFuncs) ISPMT(argsList *list.List) formulaArg {
|
||||||
return newNumberFormulaArg(num)
|
return newNumberFormulaArg(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MDURATION function calculates the Modified Macaulay Duration of a security
|
||||||
|
// that pays periodic interest, assuming a par value of $100. The syntax of
|
||||||
|
// the function is:
|
||||||
|
//
|
||||||
|
// MDURATION(settlement,maturity,coupon,yld,frequency,[basis])
|
||||||
|
//
|
||||||
|
func (fn *formulaFuncs) MDURATION(argsList *list.List) formulaArg {
|
||||||
|
args := fn.prepareDurationArgs("MDURATION", argsList)
|
||||||
|
if args.Type != ArgList {
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
duration := fn.duration(args.List[0], args.List[1], args.List[2], args.List[3], args.List[4], args.List[5])
|
||||||
|
if duration.Type != ArgNumber {
|
||||||
|
return duration
|
||||||
|
}
|
||||||
|
return newNumberFormulaArg(duration.Number / (1 + args.List[3].Number/args.List[4].Number))
|
||||||
|
}
|
||||||
|
|
||||||
// MIRR function returns the Modified Internal Rate of Return for a supplied
|
// MIRR function returns the Modified Internal Rate of Return for a supplied
|
||||||
// series of periodic cash flows (i.e. a set of values, which includes an
|
// series of periodic cash flows (i.e. a set of values, which includes an
|
||||||
// initial investment value and a series of net income values). The syntax of
|
// initial investment value and a series of net income values). The syntax of
|
||||||
|
|
30
calc_test.go
30
calc_test.go
|
@ -1472,6 +1472,8 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=DOLLARDE(1.01,16)": "1.0625",
|
"=DOLLARDE(1.01,16)": "1.0625",
|
||||||
// DOLLARFR
|
// DOLLARFR
|
||||||
"=DOLLARFR(1.0625,16)": "1.01",
|
"=DOLLARFR(1.0625,16)": "1.01",
|
||||||
|
// DURATION
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4)": "6.674422798483131",
|
||||||
// EFFECT
|
// EFFECT
|
||||||
"=EFFECT(0.1,4)": "0.103812890625",
|
"=EFFECT(0.1,4)": "0.103812890625",
|
||||||
"=EFFECT(0.025,2)": "0.02515625",
|
"=EFFECT(0.025,2)": "0.02515625",
|
||||||
|
@ -1491,6 +1493,8 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=ISPMT(0.05/12,1,60,50000)": "-204.8611111111111",
|
"=ISPMT(0.05/12,1,60,50000)": "-204.8611111111111",
|
||||||
"=ISPMT(0.05/12,2,60,50000)": "-201.38888888888886",
|
"=ISPMT(0.05/12,2,60,50000)": "-201.38888888888886",
|
||||||
"=ISPMT(0.05/12,2,1,50000)": "208.33333333333334",
|
"=ISPMT(0.05/12,2,1,50000)": "208.33333333333334",
|
||||||
|
// MDURATION
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4)": "6.543551763218756",
|
||||||
// NOMINAL
|
// NOMINAL
|
||||||
"=NOMINAL(0.025,12)": "0.0247180352381129",
|
"=NOMINAL(0.025,12)": "0.0247180352381129",
|
||||||
// NPER
|
// NPER
|
||||||
|
@ -2916,6 +2920,19 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=DOLLARFR(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=DOLLARFR(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
"=DOLLARFR(0,-1)": "#NUM!",
|
"=DOLLARFR(0,-1)": "#NUM!",
|
||||||
"=DOLLARFR(0,0)": "#DIV/0!",
|
"=DOLLARFR(0,0)": "#DIV/0!",
|
||||||
|
// DURATION
|
||||||
|
"=DURATION()": "DURATION requires 5 or 6 arguments",
|
||||||
|
"=DURATION(\"\",\"03/31/2025\",10%,8%,4)": "#VALUE!",
|
||||||
|
"=DURATION(\"04/01/2015\",\"\",10%,8%,4)": "#VALUE!",
|
||||||
|
"=DURATION(\"03/31/2025\",\"04/01/2015\",10%,8%,4)": "DURATION requires maturity > settlement",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",-1,8%,4)": "DURATION requires coupon >= 0",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",10%,-1,4)": "DURATION requires yld >= 0",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",\"\",8%,4)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",10%,\"\",4)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,3)": "#NUM!",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4,\"\")": "#NUM!",
|
||||||
|
"=DURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4,5)": "invalid basis",
|
||||||
// EFFECT
|
// EFFECT
|
||||||
"=EFFECT()": "EFFECT requires 2 arguments",
|
"=EFFECT()": "EFFECT requires 2 arguments",
|
||||||
"=EFFECT(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=EFFECT(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
@ -2964,6 +2981,19 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=ISPMT(0,\"\",0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=ISPMT(0,\"\",0,0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
"=ISPMT(0,0,\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=ISPMT(0,0,\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
"=ISPMT(0,0,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=ISPMT(0,0,0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
// MDURATION
|
||||||
|
"=MDURATION()": "MDURATION requires 5 or 6 arguments",
|
||||||
|
"=MDURATION(\"\",\"03/31/2025\",10%,8%,4)": "#VALUE!",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"\",10%,8%,4)": "#VALUE!",
|
||||||
|
"=MDURATION(\"03/31/2025\",\"04/01/2015\",10%,8%,4)": "MDURATION requires maturity > settlement",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",-1,8%,4)": "MDURATION requires coupon >= 0",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,-1,4)": "MDURATION requires yld >= 0",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",\"\",8%,4)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,\"\",4)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,3)": "#NUM!",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4,\"\")": "#NUM!",
|
||||||
|
"=MDURATION(\"04/01/2015\",\"03/31/2025\",10%,8%,4,5)": "invalid basis",
|
||||||
// NOMINAL
|
// NOMINAL
|
||||||
"=NOMINAL()": "NOMINAL requires 2 arguments",
|
"=NOMINAL()": "NOMINAL requires 2 arguments",
|
||||||
"=NOMINAL(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
"=NOMINAL(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||||
|
|
4
rows.go
4
rows.go
|
@ -774,11 +774,11 @@ func checkRow(ws *xlsxWorksheet) error {
|
||||||
//
|
//
|
||||||
// For example set style of row 1 on Sheet1:
|
// For example set style of row 1 on Sheet1:
|
||||||
//
|
//
|
||||||
// err = f.SetRowStyle("Sheet1", 1, style)
|
// err = f.SetRowStyle("Sheet1", 1, 1, styleID)
|
||||||
//
|
//
|
||||||
// Set style of rows 1 to 10 on Sheet1:
|
// Set style of rows 1 to 10 on Sheet1:
|
||||||
//
|
//
|
||||||
// err = f.SetRowStyle("Sheet1", 1, 10, style)
|
// err = f.SetRowStyle("Sheet1", 1, 10, styleID)
|
||||||
//
|
//
|
||||||
func (f *File) SetRowStyle(sheet string, start, end, styleID int) error {
|
func (f *File) SetRowStyle(sheet string, start, end, styleID int) error {
|
||||||
if end < start {
|
if end < start {
|
||||||
|
|
Loading…
Reference in New Issue