-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
feat: Added NPV, Compound Interest and Payback Period #936
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
9019283
added npv, compound interest and payback period
showmyth c202eee
fixed mod.rs errors
showmyth 8f93f28
added algos to DIRECTORY.md
showmyth d115f16
Merge branch 'master' into finstuff
siriak d29ce8c
fixed typos + removed 'return' keyword
showmyth ec6f731
made the function more idiomatic to resolve clippy warnings
showmyth 21541d8
Update src/financial/compound_interest.rs
siriak 5b64143
Merge branch 'master' into finstuff
showmyth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // compound interest is given by A = P(1+r/n)^nt | ||
| // where: A = Final Amount, P = Principal Amount, r = rate of interest, | ||
| // n = number of times interest is compounded per year and t = time (in years) | ||
|
|
||
| pub fn compound_interest(principal: f64, rate: f64, comp_per_year: u32, years: f64) -> f64 { | ||
| principal * (1.00 + rate / comp_per_year as f64).powf(comp_per_year as f64 * years) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_compound_interest() { | ||
| let principal = 1000.0; | ||
| let rate = 0.05; // 5% annual interest | ||
| let times_per_year = 4; // interest compounded quarterly | ||
| let years = 2.0; // 2 years tenure | ||
| let result = compound_interest(principal, rate, times_per_year, years); | ||
| assert!((result - 1104.486).abs() < 0.001); // expected value rounded up to 3 decimal | ||
siriak marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // places | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,8 @@ | ||
| mod compound_interest; | ||
| mod npv; | ||
| mod payback; | ||
| mod present_value; | ||
| pub use compound_interest::compound_interest; | ||
| pub use npv::npv; | ||
| pub use payback::payback; | ||
| pub use present_value::present_value; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /// Calculates Net Present Value given a vector of cash flows and a discount rate. | ||
| /// cash_flows: Vector of f64 representing cash flows for each period. | ||
| /// rate: Discount rate as an f64 (e.g., 0.05 for 5%) | ||
|
|
||
| pub fn npv(cash_flows: &[f64], rate: f64) -> f64 { | ||
| cash_flows | ||
| .iter() | ||
| .enumerate() | ||
| .map(|(t, &cf)| cf / (1.00 + rate).powi(t as i32)) | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| .sum() | ||
| } | ||
|
|
||
| // tests | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_npv_basic() { | ||
| let cash_flows = vec![-1000.0, 300.0, 400.0, -50.0]; | ||
| let rate = 0.10; | ||
| let result = npv(&cash_flows, rate); | ||
| // Calculated value ≈ -434.25 | ||
| assert!((result - (-434.25)).abs() < 0.05); // Allow small margin of error | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_npv_zero_rate() { | ||
| let cash_flows = vec![100.0, 200.0, -50.0]; | ||
| let rate = 0.0; | ||
| let result = npv(&cash_flows, rate); | ||
| assert!((result - 250.0).abs() < 0.05); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_npv_empty() { | ||
| // For empty cash flows: NPV should be 0 | ||
| let cash_flows: Vec<f64> = vec![]; | ||
| let rate = 0.05; | ||
| let result = npv(&cash_flows, rate); | ||
| assert_eq!(result, 0.0); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| /// Returns the payback period in years | ||
| /// If investment is not paid back, returns None. | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| pub fn payback(cash_flow: &[f64]) -> Option<usize> { | ||
| let mut total = 0.00; | ||
| for (year, &cf) in cash_flow.iter().enumerate() { | ||
| total += cf; | ||
| if total >= 0.00 { | ||
siriak marked this conversation as resolved.
Show resolved
Hide resolved
siriak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return Some(year); | ||
| } | ||
| } | ||
| None | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_payback() { | ||
| let cash_flows = vec![-1000.0, 300.0, 400.0, 500.0]; | ||
| assert_eq!(payback(&cash_flows), Some(3)); // paid back in year 3 | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_no_payback() { | ||
| let cash_flows = vec![-1000.0, 100.0, 100.0, 100.0]; | ||
| assert_eq!(payback(&cash_flows), None); // never paid back | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.