1 unstable release
0.0.0 | May 25, 2020 |
---|
#30 in #period
485KB
5K
SLoC
finance-solution
finance-solution is a financial library for time-value-of-money problems. 💸
People who will find this crate helpful include:
- Students of Finance who want to solve their financial problems using something better than a crude handheld calculator. Using this library also reduces the chance of human error, and provides better output and data displays than Excel.
- New developers who want to learn Rust using Finance as a topic.
- Experienced Rust developers who want to learn more about finance.
- Serious Rust developers who want to build financial software, and prefer to rely on a rigourously tested library instead of reinventing the wheel and spending hundreds of hours to develop and test their own library.
Currently, this library is geared towards the basic financial equations, regarding:
- Simple Time-Value-of-Money formulas -- this includes
present_value
,future_value
,rate
, andperiods
(known as NPER in Excel). - Cashflow Time-Value-of-Money formulas -- this includes
present_value_annuity
,future_value_annuity
,net_present_value
, andpayment
(known as PMT in Excel). - Rate conversions -- this includes all conversions between
apr
,ear
, andepr
, and also includes conversion for continuous compounding (apr_continuous
,ear_continuous
).
Examples
A business partner will give you $4,000 in 3 years. Your rate-of-return in the market is 5%. How much is the deal worth to you right now?
uses present_value()
to return f64 value
let future_value = 4_000;
let periods = 3;
let rate = 0.05;
let pv = present_value(rate, periods, future_value);
dbg!(pv);
// PRINTS TO TERMINAL:
// pv = 3455.350394125904
The crate also provides helper functions for rounding, such as
round_4
to round to four decimals places. Seeround
for more details.
For the same problem above, you can use the _solution function to see a better output and provide additional functionality.
uses present_value_solution()
to return a custom "solution" struct
let future_value = 4_000;
let periods = 3;
let rate = 0.05;
let answer = present_value_solution(rate, periods, future_value);
dbg!(answer);
// PRINTS TO TERMINAL:
// answer = TvmSolution {
// calculated_field: PresentValue,
// rate: 0.05,
// periods: 3,
// fractional_periods: 3.0,
// present_value: 3455.350394125904,
// future_value: 4000.0,
// formula: "3455.3504 = 4000.0000 / (1.050000 ^ 3)",
// formula_symbolic: "pv = fv / (1 + r)^n",
//}
If you want to explore what happens in each period of the calculation, you can use the .series()
method on any solution output:
uses present_value_solution().series()
to return a vec of each period
let future_value = 4_000;
let periods = 3;
let rate = 0.05;
let answer = present_value_solution(rate, periods, future_value);
dbg!(answer.series());
// PRINTS TO TERMINAL:
// answer.series() = TvmSeries(
// [
// TvmPeriod {
// period: 0,
// rate: 0.0,
// value: 3455.3503941259037,
// formula: "3455.3504 = 3628.1179 / 1.050000",
// formula_symbolic: "value = {next period value} / (1 + r)",
// },
// TvmPeriod {
// period: 1,
// rate: 0.05,
// value: 3628.117913832199,
// formula: "3628.1179 = 3809.5238 / 1.050000",
// formula_symbolic: "value = {next period value} / (1 + r)",
// },
// TvmPeriod {
// period: 2,
// rate: 0.05,
// value: 3809.523809523809,
// formula: "3809.5238 = 4000.0000 / 1.050000",
// formula_symbolic: "value = {next period value} / (1 + r)",
// },
// TvmPeriod {
// period: 3,
// rate: 0.05,
// value: 4000.0,
// formula: "4000.0000",
// formula_symbolic: "value = fv",
// },
// ],
// )
To view each period in a table format, use the .print_table()
method.
uses present_value_solution().series().print_table()
to return a pretty-print table
use num_format::{Locale};
let future_value = 4_000;
let periods = 3;
let rate = 0.05;
let answer = present_value_solution(rate, periods, future_value);
dbg!(answer.series().print_table());
// or use .print_table_locale() to specify your formatting preferences.
dbg!(answer.series().print_table_locale(&Locale::en, 4));
// PRINTS TO TERMINAL:
// period rate value
// ------ ------ ----------
// 0 0.0000 3,455.3504
// 1 0.0500 3,628.1179
// 2 0.0500 3,809.5238
// 3 0.0500 4,000.0000
In the table above, you can specify the locale, if you prefer a different format for the money values. For example, your country may prefer 8.532,11
instead of 8,532.11
. The pretty-printed tables are easily copy&pasted into a spreadsheet.
The .print_table()
function can be especially helpful when analyzing payment
and cashflow
information.
uses payment_solution().series().print_table()
to return a pretty-print table
let present_value = 13_000;
let periods = 5;
let rate = 0.08;
let answer = payment_solution(rate, periods, present_value, 0);
dbg!(answer.series().print_table());
// PRINTS TO TERMINAL:
// period payments_to_date payments_remaining principal principal_to_date principal_remaining interest interest_to_date interest_remaining
// ------ ---------------- ------------------ ----------- ----------------- ------------------- ----------- ---------------- ------------------
// 1 -3,255.9339 -13,023.7356 -2,215.9339 -2,215.9339 -10,784.0661 -1,040.0000 -1,040.0000 -2,239.6695
// 2 -6,511.8678 -9,767.8017 -2,393.2086 -4,609.1425 -8,390.8575 -862.7253 -1,902.7253 -1,376.9443
// 3 -9,767.8017 -6,511.8678 -2,584.6653 -7,193.8078 -5,806.1922 -671.2686 -2,573.9939 -705.6757
// 4 -13,023.7356 -3,255.9339 -2,791.4385 -9,985.2464 -3,014.7536 -464.4954 -3,038.4893 -241.1803
// 5 -16,279.6695 0.0000 -3,014.7536 -12,999.0000 -0.0000 -241.1803 -3,279.6695 0.0000
As you can see in the table above, the finance-solution
library offers more than "just the answer" to the problem (-3,255.9339) but also provides a detailed visual of what is happening in each period.
Benefits of using finance-solution
This library has undergone hundreds of hours spent designing the library to be ergonomic, rustic, and accurate.
Bonus highlights include:
- finance-solution provides both f64 functions almost all functions can add
_solution
to the function name to provide a more helpful output, with additional functionality. We highly recommend you use the_solution
functions when you can! - the
_solution
structs add a trivial amount of time to the code execution, 12-30 nanoseconds... as shown in ourbenches
section. - all the formulas have been rigorously tested, both in unit tests, integration tests, and "symmetry" tests.
- function parameters follow consistent ordering when possible, for example "rate, periods, ..." so the user can almost guess the ordering of parameters.
- table output of
_solution().series().print_table()
allows the user to specify locale for specific currency formatting, and the output can easily be copy&pasted into spreadsheets (Excel, Google Sheet, etc). - Sample word problems are provided in the
examples
folder of the repo, which allows users to see how finance-solution can be used to solve financial problems. - Functions have built-in asserts, panics, and even
warn!
logs to prevent users from making common mistakes, especially with rates. - Functions are built for ease-of-use, so the user can provide f64 or f32 or u32 or i8... Any numeric format for money is accepted into the function and converted into f64, for user convenience.
- Functional parameters like rate and periods are strictly enforced to f64 for rate and u32 for periods. Periods are not allowed to be negative, and periods larger than 2000 will likely lead to computer-inherent floating point representation errors, so we provide a
warn!
for situations when we believe the inputs may create inaccuracies in the final output. It is up to the user to enable warn logs.
To-do items for this crate
We have a backlog of items we intend to include in this crate:
- IRR
- MIRR
- WACC
- PV and FV annuity schedules (varying rates and cashflows)
- Payback Period
- Profitability Index
- Return on investment
- Amortization
- PPMT
- IPMT
- Perpetuities
- CUMPRINC
- CUMIPMT
- Bonds
- ROI
- Rule of 72 (and related fns)
- SLN
- XNPV
- XIRR
Dependencies
~4–12MB
~132K SLoC