eba6ea6762
Create a finance module to help me cheaply calculate things like the future value of a Spotify subscription or Dropbox subscription or Jiu Jitsu membership.
119 lines
4.2 KiB
EmacsLisp
119 lines
4.2 KiB
EmacsLisp
;;; finance.el --- Functions to help me organize my finances -*- lexical-binding: t -*-
|
|
;; Author: William Carroll <wpcarro@gmail.com>
|
|
|
|
;;; Commentary:
|
|
;; Using functions to organize my financial thinking.
|
|
|
|
;;; Code:
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Dependencies
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(require 'prelude)
|
|
(require 'math)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Library
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defvar finance/enable-tests? t
|
|
"When t, run the tests defined herein.")
|
|
|
|
;; TODO: Support printing an org-table of these amount in a similar format to:
|
|
;; https://keisan.casio.com/exec/system/1234231998
|
|
(cl-defun finance/future-value (amt
|
|
&key
|
|
num-years
|
|
(frequency 'monthly)
|
|
(interest-rate 0.06)
|
|
(payment-due-at 'beg)
|
|
(present-value 0))
|
|
"Compute the Future Value of AMT.
|
|
|
|
This function assumes that the interest rate is applied annually and not
|
|
monthly.
|
|
|
|
This function will attempt to provide the following defaults:
|
|
- frequency: 'monthly
|
|
- interest-rate: 6%
|
|
- payment-due-at: 'beg
|
|
- present-value: 0.00"
|
|
(prelude/assert (set/contains? payment-due-at (set/new 'beg 'end)))
|
|
(prelude/assert (set/contains? frequency (set/new 'annually
|
|
'semiannually
|
|
'quarterly
|
|
'monthly)))
|
|
(let ((pmt amt)
|
|
(k (alist/get frequency '((annually . 1)
|
|
(semiannually . 2)
|
|
(quarterly . 4)
|
|
(monthly . 12))))
|
|
(r interest-rate)
|
|
(n num-years)
|
|
(pv present-value))
|
|
(if (= 0 r)
|
|
(+ pv (* pmt n k))
|
|
(if (equal 'beg payment-due-at)
|
|
(+ (* pv (math/exp (+ 1 (/ r k)) (* n k)))
|
|
(* pmt
|
|
(/ (- (math/exp (+ 1 (/ r k)) (* n k)) 1)
|
|
(/ r k))
|
|
(+ 1 (/ r k))))
|
|
(+ (* pv (math/exp (+ 1 (/ r k)) (* n k)))
|
|
(* pmt
|
|
(/ (- (math/exp (+ 1 (/ r k)) (* n k)) 1)
|
|
(/ r k))))))))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Tests
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(when finance/enable-tests?
|
|
(prelude/assert
|
|
(equal "1551.27"
|
|
(string/format "%0.2f"
|
|
(finance/future-value
|
|
9.99
|
|
:interest-rate 0.05
|
|
:num-years 10
|
|
:frequency 'monthly
|
|
:payment-due-at 'end
|
|
:present-value 0))))
|
|
(prelude/assert
|
|
(equal "14318.34"
|
|
(string/format "%0.2f"
|
|
(finance/future-value 10.0 :num-years 35))))
|
|
(prelude/assert
|
|
(equal "4200.00"
|
|
(string/format "%0.2f"
|
|
(finance/future-value
|
|
10.0
|
|
:interest-rate 0.0
|
|
:num-years 35
|
|
:frequency 'monthly
|
|
:payment-due-at 'beg
|
|
:present-value 0))))
|
|
(prelude/assert
|
|
(equal "14318.34"
|
|
(string/format "%0.2f"
|
|
(finance/future-value
|
|
10.0
|
|
:interest-rate 0.06
|
|
:num-years 35
|
|
:frequency 'monthly
|
|
:payment-due-at 'beg
|
|
:present-value 0))))
|
|
(prelude/assert
|
|
(equal "38282.77"
|
|
(string/format "%0.2f"
|
|
(finance/future-value
|
|
10.0
|
|
:interest-rate 0.1
|
|
:num-years 35
|
|
:frequency 'monthly
|
|
:payment-due-at 'beg
|
|
:present-value 0)))))
|
|
|
|
(provide 'finance)
|
|
;;; finance.el ends here
|