Skip to content

Commit

Permalink
benchmark on data more similar to real ones
Browse files Browse the repository at this point in the history
  • Loading branch information
Anexen committed Jan 28, 2024
1 parent 43a7d18 commit 6cb556d
Show file tree
Hide file tree
Showing 7 changed files with 1,696 additions and 23 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ and the [implementation from the Stack Overflow](https://stackoverflow.com/a/115

![bench](https://raw.githubusercontent.com/Anexen/pyxirr/main/docs/static/bench.png)

PyXIRR is ~10-20x faster in XIRR calculation than the other implementations.
PyXIRR is much faster in XIRR calculation than the other implementations.

Powered by [github-action-benchmark](https://github.com/rhysd/github-action-benchmark) and [plotly.js](https://github.com/plotly/plotly.js).
Powered by [github-action-benchmark](https://github.com/benchmark-action/github-action-benchmark) and [plotly.js](https://github.com/plotly/plotly.js).

Live benchmarks are hosted on [Github Pages](https://anexen.github.io/pyxirr/bench).

Expand Down
1 change: 0 additions & 1 deletion bench-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
scipy==1.*
numpy-financial==1.*
xirr==0.1.6
60 changes: 40 additions & 20 deletions benches/comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod common;
use common::PaymentsLoader;

// https://stackoverflow.com/questions/8919718/financial-python-library-that-has-xirr-and-xnpv-function
const TOP_STACK_OVERFLOW_ANSWER: &str = r#"
const PURE_PYTHON_IMPL: &str = r#"
def xirr(transactions):
years = [(ta[0] - transactions[0][0]).days / 365.0 for ta in transactions]
residual = 1
Expand All @@ -32,13 +32,29 @@ def xirr(transactions):
return guess
"#;

const SCIPY_IMPL: &str = r#"
import scipy.optimize
def xnpv(rate, values, dates):
if rate <= -1.0:
return float('inf')
d0 = dates[0] # or min(dates)
return sum([ vi / (1.0 + rate)**((di - d0).days / 365.0) for vi, di in zip(values, dates)])
def xirr(values, dates):
try:
return scipy.optimize.newton(lambda r: xnpv(r, values, dates), 0.0)
except RuntimeError: # Failed to converge?
return scipy.optimize.brentq(lambda r: xnpv(r, values, dates), -1.0, 1e10)
"#;

macro_rules! bench_rust {
($name:ident, $file:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
Python::with_gil(|py| {
let data = PaymentsLoader::from_csv(py, $file).to_records();
b.iter(|| pyxirr_call_impl!(py, "xirr", (data,)).unwrap());
b.iter(|| pyxirr_call_impl!(py, "xirr", black_box((data,))).unwrap());
});
}
};
Expand All @@ -49,10 +65,12 @@ macro_rules! bench_scipy {
#[bench]
fn $name(b: &mut Bencher) {
Python::with_gil(|py| {
let xirr =
py.import("xirr").expect("xirr is not installed").getattr("xirr").unwrap();
let data = PaymentsLoader::from_csv(py, $file).to_dict();
b.iter(|| xirr.call1(black_box((data,))).unwrap())
let xirr = PyModule::from_code(py, SCIPY_IMPL, "xirr.py", "scipy_py_xirr")
.unwrap()
.getattr("xirr")
.unwrap();
let data = PaymentsLoader::from_csv(py, $file).to_columns();
b.iter(|| xirr.call1(black_box((data.1, data.0))).unwrap())
});
}
};
Expand All @@ -63,26 +81,28 @@ macro_rules! bench_python {
#[bench]
fn $name(b: &mut Bencher) {
Python::with_gil(|py| {
let xirr =
PyModule::from_code(py, TOP_STACK_OVERFLOW_ANSWER, "xirr.py", "pure_py_xirr")
.unwrap()
.getattr("xirr")
.unwrap();
let xirr = PyModule::from_code(py, PURE_PYTHON_IMPL, "xirr.py", "pure_py_xirr")
.unwrap()
.getattr("xirr")
.unwrap();
let data = PaymentsLoader::from_csv(py, $file).to_records();
b.iter(|| xirr.call1(black_box((data,))).unwrap())
});
}
};
}

bench_rust!(bench_rust_100, "tests/samples/random_100.csv");
bench_rust!(bench_rust_500, "tests/samples/random_500.csv");
bench_rust!(bench_rust_1000, "tests/samples/random_1000.csv");
bench_rust!(bench_rust_50, "tests/samples/rw-50.csv");
bench_rust!(bench_rust_100, "tests/samples/rw-100.csv");
bench_rust!(bench_rust_500, "tests/samples/rw-500.csv");
bench_rust!(bench_rust_1000, "tests/samples/rw-1000.csv");

bench_scipy!(bench_scipy_100, "tests/samples/random_100.csv");
bench_scipy!(bench_scipy_500, "tests/samples/random_500.csv");
bench_scipy!(bench_scipy_1000, "tests/samples/random_1000.csv");
bench_scipy!(bench_scipy_50, "tests/samples/rw-50.csv");
bench_scipy!(bench_scipy_100, "tests/samples/rw-100.csv");
bench_scipy!(bench_scipy_500, "tests/samples/rw-500.csv");
bench_scipy!(bench_scipy_1000, "tests/samples/rw-1000.csv");

bench_python!(bench_python_100, "tests/samples/random_100.csv");
bench_python!(bench_python_500, "tests/samples/random_500.csv");
bench_python!(bench_python_1000, "tests/samples/random_1000.csv");
bench_python!(bench_python_50, "tests/samples/rw-50.csv");
bench_python!(bench_python_100, "tests/samples/rw-100.csv");
bench_python!(bench_python_500, "tests/samples/rw-500.csv");
bench_python!(bench_python_1000, "tests/samples/rw-1000.csv");
101 changes: 101 additions & 0 deletions tests/samples/rw-100.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
2000-01-01,-1000000.0
2000-01-01,10365.378864363389
2000-01-31,14815.415470294169
2000-03-01,12030.562733418017
2000-03-31,11307.979942311524
2000-04-30,17393.026477395906
2000-05-30,10111.520084997483
2000-06-29,11777.760495889588
2000-07-29,9425.622181866325
2000-08-28,15628.377143997544
2000-09-27,9702.463005875723
2000-10-27,15856.679956400441
2000-11-26,7536.830552079986
2000-12-26,15610.748972849195
2001-01-25,12244.61630572664
2001-02-24,11440.499598220922
2001-03-26,16389.68889989676
2001-04-25,8924.054568318044
2001-05-25,14793.134925800208
2001-06-24,16036.87407471702
2001-07-24,11774.764247927264
2001-08-23,10148.729650154515
2001-09-22,15523.43345913048
2001-10-22,12968.672606115631
2001-11-21,13295.228164108466
2001-12-21,17234.0533865184
2002-01-20,12855.582301574757
2002-02-19,11332.650415145608
2002-03-21,10340.065865024482
2002-04-20,10809.698350285784
2002-05-20,9416.931526240587
2002-06-19,10980.441703375955
2002-07-19,10292.951072761207
2002-08-18,17249.589174226494
2002-09-17,12084.28998231004
2002-10-17,9315.538003932472
2002-11-16,8609.349472916037
2002-12-16,14691.770706542706
2003-01-15,8450.698171422924
2003-02-14,12948.035349790975
2003-03-16,13530.318420038606
2003-04-15,14538.323495605848
2003-05-15,12046.162449959194
2003-06-14,10832.319130654103
2003-07-14,16495.616055439532
2003-08-13,10676.879107776198
2003-09-12,12090.198592563082
2003-10-12,10646.566503179505
2003-11-11,10488.917821443225
2003-12-11,10821.398073651553
2004-01-10,13796.07016032582
2004-02-09,17230.011611409267
2004-03-10,11194.995563445955
2004-04-09,11814.34556830408
2004-05-09,13608.376888722712
2004-06-08,10594.307904257505
2004-07-08,10166.765732386435
2004-08-07,15833.016943050037
2004-09-06,9200.039765804853
2004-10-06,8350.800836539574
2004-11-05,15658.541973800531
2004-12-05,9509.214362555325
2005-01-04,14532.667944151059
2005-02-03,10309.61112254181
2005-03-05,10443.534156861997
2005-04-04,14842.312924625034
2005-05-04,15038.568489678159
2005-06-03,15255.677522253782
2005-07-03,16223.787124615072
2005-08-02,15192.052628098396
2005-09-01,8841.623001019849
2005-10-01,13192.253118052433
2005-10-31,12111.569405373712
2005-11-30,14887.156246485036
2005-12-30,12544.271309525768
2006-01-29,16024.132284414649
2006-02-28,16663.25391795901
2006-03-30,14377.096445477888
2006-04-29,10062.345942299968
2006-05-29,11771.472692254092
2006-06-28,17496.750504429547
2006-07-28,10988.45972418063
2006-08-27,17348.837398907228
2006-09-26,12367.24713060131
2006-10-26,9765.378568208846
2006-11-25,15891.886411452715
2006-12-25,12518.086311310873
2007-01-24,8509.677591501983
2007-02-23,8648.4031376079
2007-03-25,13248.069865865491
2007-04-24,15967.767234625975
2007-05-24,8475.297565914076
2007-06-23,16178.5238769798
2007-07-23,10091.194073369616
2007-08-22,10581.218629853609
2007-09-21,11733.279338775046
2007-10-21,12099.24135653874
2007-11-20,14814.894928569258
2007-12-20,13927.990551005641
2008-01-19,14406.157556095503
2008-02-18,16770.931116091037
Loading

0 comments on commit 6cb556d

Please sign in to comment.