diff --git a/README.md b/README.md index 324b946..f07ccae 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ c.Restore(state) | Arithmetic | `Add`, `Sub`, `Mul`, `Div`, `YPowX` | | TVM store | `SetN`, `SetI`, `SetPV`, `SetPMT`, `SetFV` | | TVM solve | `SolveN`, `SolveI`, `SolvePV`, `SolvePMT`, `SolveFV` | -| Cash flow | `ComputeNPV`, `ComputeIRR` | +| Cash flow | `NPV`, `IRR` | | Amortization | `Amortize` | | Bonds | `BondPrice`, `BondYield` | | Depreciation | `DepreciationSL`, `DepreciationSOYD`, `DepreciationDB` | @@ -144,6 +144,7 @@ c.Program, c.PgmLen, c.PgmPC // program storage ```bash go run examples/mortgage/main.go # $300K mortgage payment +go run examples/solve-tvm/main.go # unified TVM solver go run examples/npv/main.go # NPV + IRR go run examples/fv/main.go # future value go run examples/stats/main.go # statistics (engine) diff --git a/calculator.go b/calculator.go index 0bdaa27..83eb848 100644 --- a/calculator.go +++ b/calculator.go @@ -189,9 +189,9 @@ func (c *CalcService) solveTVM(op string) { func (c *CalcService) unprefixed(op string, arg float64) { switch op { case "NPV": - c.e.ComputeNPV() + c.e.NPV() case "IRR": - c.e.ComputeIRR() + c.e.IRR() case "PRICE": c.e.BondPrice() case "YTM": @@ -301,9 +301,9 @@ func (c *CalcService) fPrefixed(op string, arg float64, argS string) { case "INT": c.e.X = c.e.AmortInt case "NPV": - c.e.ComputeNPV() + c.e.NPV() case "IRR": - c.e.ComputeIRR() + c.e.IRR() case "PRICE": c.e.BondPrice() case "YTM": diff --git a/engine/engine_test.go b/engine/engine_test.go index 1c24bfb..033f923 100644 --- a/engine/engine_test.go +++ b/engine/engine_test.go @@ -310,7 +310,7 @@ func TestNPVAndIRR(t *testing.T) { e.FinCFj[2] = 70 e.FinCfCnt = 3 e.X = 10 - e.ComputeNPV() + e.NPV() if math.Abs(e.X-47.63) > 0.1 { t.Fatalf("NPV: want ~47.63, got %v", e.X) } @@ -320,7 +320,7 @@ func TestNPVAndIRR(t *testing.T) { e.FinCFj[1] = 60 e.FinCfCnt = 2 e.Flags.StackLift = true - e.ComputeIRR() + e.IRR() if math.Abs(e.X-13.07) > 0.5 { t.Fatalf("IRR: want ~13.07, got %v", e.X) } diff --git a/engine/example_test.go b/engine/example_test.go index 3bd1952..81d7a83 100644 --- a/engine/example_test.go +++ b/engine/example_test.go @@ -45,7 +45,7 @@ func Example_npv() { c.FinCfCnt = 4 c.X = 10 c.Flags.StackLift = true - c.ComputeNPV() + c.NPV() fmt.Printf("NPV: $%.2f\n", c.X) // Output: NPV: $38877.13 @@ -60,7 +60,7 @@ func Example_irr() { c.FinCFj[2] = 30000 c.FinCfCnt = 3 c.Flags.StackLift = true - c.ComputeIRR() + c.IRR() fmt.Printf("IRR: %.2f%%\n", c.X) // Output: IRR: 10.13% @@ -174,7 +174,7 @@ func TestExamples(t *testing.T) { c.FinCfCnt = 4 c.X = 10 c.Flags.StackLift = true - c.ComputeNPV() + c.NPV() if math.Abs(c.X-38877.13) > 1 { t.Fatalf("NPV: want ~38877, got %v", c.X) } @@ -188,7 +188,7 @@ func TestExamples(t *testing.T) { c.FinCFj[2] = 30000 c.FinCfCnt = 3 c.Flags.StackLift = true - c.ComputeIRR() + c.IRR() if math.Abs(c.X-10.13) > 0.5 { t.Fatalf("IRR: want ~10.13, got %v", c.X) } diff --git a/engine/financial.go b/engine/financial.go index c7f3d85..cb094ac 100644 --- a/engine/financial.go +++ b/engine/financial.go @@ -99,12 +99,12 @@ func (e *Engine) cashflows() []float64 { return cfs } -func (e *Engine) ComputeNPV() { +func (e *Engine) NPV() { e.X = clamp(NPV(e.X/100, e.cashflows()...)) e.Flags.StackLift = true } -func (e *Engine) ComputeIRR() { +func (e *Engine) IRR() { r, _ := IRR(e.cashflows()...) e.result(r * 100) } diff --git a/engine/regress_test.go b/engine/regress_test.go index 8294a89..8adbe9c 100644 --- a/engine/regress_test.go +++ b/engine/regress_test.go @@ -31,7 +31,7 @@ func TestRegressNPV_ConsumesRate(t *testing.T) { e.Y = 2 e.X = 10 e.Flags.StackLift = true - e.ComputeNPV() + e.NPV() if math.Abs(e.X-47.63) > 0.1 { t.Fatalf("X=%v", e.X) } diff --git a/examples/solve-tvm/main.go b/examples/solve-tvm/main.go new file mode 100644 index 0000000..074ad47 --- /dev/null +++ b/examples/solve-tvm/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "math" + + "github.com/shanehull/dozen/engine" +) + +func main() { + // $300K mortgage, 30 years, monthly payment of $1,798.65. + // What's the APR? Pass NaN for the unknown. + i, _ := engine.SolveTVM(360, math.NaN(), 300000, -1798.65, 0, engine.End) + fmt.Printf("Rate: %.2f%% APR\n", i*12*100) + + // How many months to pay off with $2,000/mo? + n, _ := engine.SolveTVM(math.NaN(), 0.06/12, 300000, -2000, 0, engine.End) + fmt.Printf("Term: %.0f months at $2,000/mo\n", n) + + // What loan can I afford at $1,500/mo over 30 years? + pv, _ := engine.SolveTVM(360, 0.06/12, math.NaN(), -1500, 0, engine.End) + fmt.Printf("Loan: $%.0f\n", pv) +}