https://github.com/anexen/pyxirr

Rust-powered collection of financial functions.

https://github.com/anexen/pyxirr

Science Score: 26.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (13.3%) to scientific vocabulary

Keywords

day-count fast financial-analysis financial-functions isda maturin numpy pme private-equity pyo3 python python-extension rust xirr xirr-calculation xnpv
Last synced: 6 months ago · JSON representation

Repository

Rust-powered collection of financial functions.

Basic Info
Statistics
  • Stars: 196
  • Watchers: 8
  • Forks: 23
  • Open Issues: 6
  • Releases: 29
Topics
day-count fast financial-analysis financial-functions isda maturin numpy pme private-equity pyo3 python python-extension rust xirr xirr-calculation xnpv
Created almost 5 years ago · Last pushed 6 months ago
Metadata Files
Readme Changelog Funding License

README.md

rust-lang.org License pypi versions

PyXIRR

Rust-powered collection of financial functions.

PyXIRR stands for "Python XIRR" (for historical reasons), but contains many other financial functions such as IRR, FV, NPV, etc.

Features:

  • correct
  • supports different day count conventions (e.g. ACT/360, 30E/360, etc.)
  • works with different input data types (iterators, numpy arrays, pandas DataFrames)
  • no external dependencies
  • type annotations
  • blazingly fast

Installation

pip install pyxirr

WASM wheels for pyodide are also available, but unfortunately are not supported by PyPI. You can find them on the GitHub Releases page.

Benchmarks

Rust implementation has been tested against existing xirr package (uses scipy.optimize under the hood) and the implementation from the Stack Overflow (pure python).

bench

PyXIRR is much faster than the other implementations.

Powered by github-action-benchmark and plotly.js.

Live benchmarks are hosted on Github Pages.

Example

```python from datetime import date from pyxirr import xirr

dates = [date(2020, 1, 1), date(2021, 1, 1), date(2022, 1, 1)] amounts = [-1000, 750, 500]

feed columnar data

xirr(dates, amounts)

feed iterators

xirr(iter(dates), (x / 2 for x in amounts))

feed an iterable of tuples

xirr(zip(dates, amounts))

feed a dictionary

xirr(dict(zip(dates, amounts)))

dates as strings

xirr(['2020-01-01', '2021-01-01'], [-1000, 1200]) ```

Multiple IRR problem

The Multiple IRR problem occurs when the signs of cash flows change more than once. In this case, we say that the project has non-conventional cash flows. This leads to situation, where it can have more the one IRR or have no IRR at all.

PyXIRR addresses the Multiple IRR problem as follows:

  1. It looks for positive result around 0.1 (the same as Excel with the default guess=0.1).
  2. If it can't find a result, it uses several other attempts and selects the lowest IRR to be conservative.

Here is an example illustrating how to identify multiple IRRs:

```python import numpy as np import pyxirr

load cash flow:

cf = pd.read_csv("tests/samples/30-22.csv", names=["date", "amount"])

check whether the cash flow is conventional:

print(pyxirr.isconventionalcash_flow(cf["amount"])) # false

build NPV profile:

calculate 50 NPV values for different rates

rates = np.linspace(-0.5, 0.5, 50)

any iterable, any rates, e.g.

rates = [-0.5, -0.3, -0.1, 0.1, -0.6]

values = pyxirr.xnpv(rates, cf)

print NPV profile:

NPV changes sign two times:

1) between -0.316 and -0.295

2) between -0.03 and -0.01

print("NPV profile:") for rate, value in zip(rates, values): print(rate, value)

plot NPV profile

import pandas as pd series = pd.Series(values, index=rates) pd.DataFrame(series[series > -1e6]).assign(zero=0).plot()

find points where NPV function crosses zero

indexes = pyxirr.zerocrossingpoints(values)

print("Zero crossing points:") for idx in indexes: print("between", rates[idx], "and", rates[idx+1])

XIRR has two results:

-0.31540826742734207

-0.028668460065441048

for i, idx in enumerate(indexes, start=1): rate = pyxirr.xirr(cf, guess=rates[idx]) npv = pyxirr.xnpv(rate, cf) print(f"{i}) {rate}; XNPV = {npv}") ```

More Examples

Numpy and Pandas

```python import numpy as np import pandas as pd

feed numpy array

xirr(np.array([dates, amounts])) xirr(np.array(dates), np.array(amounts))

feed DataFrame (columns names doesn't matter; ordering matters)

xirr(pd.DataFrame({"a": dates, "b": amounts}))

feed Series with DatetimeIndex

xirr(pd.Series(amounts, index=pd.to_datetime(dates)))

bonus: apply xirr to a DataFrame with DatetimeIndex:

df = pd.DataFrame( index=pd.date_range("2021", "2022", freq="MS", inclusive="left"), data={ "one": [-100] + [20] * 11, "two": [-80] + [19] * 11, }, ) df.apply(xirr) # Series(index=["one", "two"], data=[5.09623547168478, 8.780801977141174]) ```

Day count conventions

Check out the available options on the docs/day-count-conventions.

```python from pyxirr import DayCount

xirr(dates, amounts, daycount=DayCount.ACT360)

parse day count from string

xirr(dates, amounts, day_count="30E/360") ```

Private equity performance metrics

```python from pyxirr import pe

pe.pme_plus([-20, 15, 0], index=[100, 115, 130], nav=20)

pe.direct_alpha([-20, 15, 0], index=[100, 115, 130], nav=20) ```

Docs

Other financial functions

```python import pyxirr

Future Value

pyxirr.fv(0.05/12, 10*12, -100, -100)

Net Present Value

pyxirr.npv(0, [-40000, 5000, 8000, 12000, 30_000])

IRR

pyxirr.irr([-100, 39, 59, 55, 20])

... and more! Check out the docs.

```

Docs

Vectorization

PyXIRR supports numpy-like vectorization.

If all input is scalar, returns a scalar float. If any input is arraylike, returns values for each input element. If multiple inputs are arraylike, performs broadcasting and returns values for each element.

```python import pyxirr

feed list

pyxirr.fv([0.05/12, 0.06/12], 1012, -100, -100) pyxirr.fv([0.05/12, 0.06/12], [1012, 9*12], [-100, -200], -100)

feed numpy array

import numpy as np rates = np.array([0.05, 0.06, 0.07])/12 pyxirr.fv(rates, 10*12, -100, -100)

feed any iterable!

pyxirr.fv( np.linspace(0.01, 0.2, 10), (x + 1 for x in range(10)), range(-100, -1100, -100), tuple(range(-100, -200, -10)) )

2d, 3d, 4d, and more!

rates = [[[[[[0.01], [0.02]]]]]] pyxirr.fv(rates, 10*12, -100, -100) ```

API reference

See the docs

Roadmap

  • [x] Implement all functions from numpy-financial
  • [x] Improve docs, add more tests
  • [x] Type hints
  • [x] Vectorized versions of numpy-financial functions.
  • [ ] Compile library for rust/javascript/python

Development

Running tests with pyo3 is a bit tricky. In short, you need to compile your tests without extension-module feature to avoid linking errors. See the following issues for the details: #341, #771.

If you are using pyenv, make sure you have the shared library installed (check for ${PYENV_ROOT}/versions/<version>/lib/libpython3.so file).

bash $ PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install <version>

Install dev-requirements

bash $ pip install -r dev-requirements.txt

Building

bash $ maturin develop

Testing

bash $ LD_LIBRARY_PATH=${PYENV_ROOT}/versions/3.10.8/lib cargo test

Benchmarks

bash $ pip install -r bench-requirements.txt $ LD_LIBRARY_PATH=${PYENV_ROOT}/versions/3.10.8/lib cargo +nightly bench

Building and distribution

This library uses maturin to build and distribute python wheels.

bash $ docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin build --release --manylinux 2010 --strip $ maturin upload target/wheels/pyxirr-${version}*

Owner

  • Name: Alexander Volkovsky
  • Login: Anexen
  • Kind: user

GitHub Events

Total
  • Issues event: 11
  • Watch event: 27
  • Delete event: 1
  • Issue comment event: 15
  • Push event: 17
  • Pull request event: 3
  • Fork event: 5
  • Create event: 3
Last Year
  • Issues event: 11
  • Watch event: 27
  • Delete event: 1
  • Issue comment event: 15
  • Push event: 17
  • Pull request event: 3
  • Fork event: 5
  • Create event: 3

Committers

Last synced: 9 months ago

All Time
  • Total Commits: 213
  • Total Committers: 7
  • Avg Commits per committer: 30.429
  • Development Distribution Score (DDS): 0.244
Past Year
  • Commits: 20
  • Committers: 2
  • Avg Commits per committer: 10.0
  • Development Distribution Score (DDS): 0.25
Top Committers
Name Email Commits
Anexen a****3@g****m 161
github-action-benchmark g****b 47
amotzop 1****p 1
Viktor Holmqvist v****t@g****m 1
Nikita Almakov n****v@g****m 1
Mart van de Ven t****k 1
Bernardo Cordeiro b****o 1

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 43
  • Total pull requests: 28
  • Average time to close issues: 27 days
  • Average time to close pull requests: 1 day
  • Total issue authors: 36
  • Total pull request authors: 8
  • Average comments per issue: 2.16
  • Average comments per pull request: 0.5
  • Merged pull requests: 24
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 10
  • Pull requests: 3
  • Average time to close issues: 3 days
  • Average time to close pull requests: 2 days
  • Issue authors: 10
  • Pull request authors: 2
  • Average comments per issue: 1.2
  • Average comments per pull request: 1.67
  • Merged pull requests: 1
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • Peque (4)
  • askmedov (2)
  • JoshCleaverEmpire (2)
  • pmenegas (2)
  • yonil7 (2)
  • adhimmulia (1)
  • dytttf (1)
  • duboisbarron (1)
  • ma-gh (1)
  • PAgrawal16 (1)
  • vlcp197 (1)
  • yellowbean (1)
  • paulfri (1)
  • BrendoCosta (1)
  • gp-bma (1)
Pull Request Authors
  • Anexen (21)
  • agriyakhetarpal (2)
  • reneoctavio (1)
  • amotzop (1)
  • tijptjik (1)
  • westandskif (1)
  • harkylton (1)
  • bernardofcordeiro (1)
  • rbusquet (1)
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 3
  • Total downloads:
    • pypi 381,758 last-month
  • Total docker downloads: 627
  • Total dependent packages: 6
    (may contain duplicates)
  • Total dependent repositories: 9
    (may contain duplicates)
  • Total versions: 37
  • Total maintainers: 2
pypi.org: pyxirr

Rust-powered collection of financial functions for Python.

  • Versions: 33
  • Dependent Packages: 6
  • Dependent Repositories: 9
  • Downloads: 381,719 Last month
  • Docker Downloads: 627
Rankings
Downloads: 0.9%
Dependent packages count: 2.1%
Dependent repos count: 4.9%
Average: 5.1%
Stargazers count: 6.4%
Forks count: 11.0%
Maintainers (1)
Last synced: 6 months ago
pypi.org: excele-xirr

Rust-powered collection of financial functions for Python.

  • Versions: 1
  • Dependent Packages: 0
  • Dependent Repositories: 0
  • Downloads: 39 Last month
Rankings
Stargazers count: 6.6%
Dependent packages count: 9.3%
Forks count: 10.0%
Average: 19.5%
Dependent repos count: 52.1%
Maintainers (1)
Last synced: 6 months ago
conda-forge.org: pyxirr
  • Versions: 3
  • Dependent Packages: 0
  • Dependent Repositories: 0
Rankings
Stargazers count: 33.0%
Dependent repos count: 34.0%
Average: 41.5%
Forks count: 47.7%
Dependent packages count: 51.2%
Last synced: 6 months ago

Dependencies

Cargo.lock cargo
  • autocfg 1.1.0
  • bitflags 1.3.2
  • cfg-if 1.0.0
  • futures 0.3.21
  • futures-channel 0.3.21
  • futures-core 0.3.21
  • futures-executor 0.3.21
  • futures-io 0.3.21
  • futures-macro 0.3.21
  • futures-sink 0.3.21
  • futures-task 0.3.21
  • futures-timer 3.0.2
  • futures-util 0.3.21
  • indoc 1.0.6
  • libc 0.2.126
  • lock_api 0.4.7
  • matrixmultiply 0.3.2
  • memchr 2.5.0
  • ndarray 0.15.4
  • num-complex 0.4.2
  • num-integer 0.1.45
  • num-traits 0.2.15
  • num_threads 0.1.6
  • numpy 0.16.2
  • once_cell 1.13.0
  • parking_lot 0.12.1
  • parking_lot_core 0.9.3
  • pin-project-lite 0.2.9
  • pin-utils 0.1.0
  • proc-macro2 1.0.40
  • pyo3 0.16.5
  • pyo3-build-config 0.16.5
  • pyo3-ffi 0.16.5
  • pyo3-macros 0.16.5
  • pyo3-macros-backend 0.16.5
  • quote 1.0.20
  • rawpointer 0.2.1
  • redox_syscall 0.2.13
  • rstest 0.15.0
  • rstest_macros 0.14.0
  • rustc_version 0.4.0
  • scopeguard 1.1.0
  • semver 1.0.12
  • slab 0.4.7
  • smallvec 1.9.0
  • syn 1.0.98
  • target-lexicon 0.12.4
  • time 0.3.11
  • time-macros 0.2.4
  • unicode-ident 1.0.2
  • unindent 0.1.9
  • windows-sys 0.36.1
  • windows_aarch64_msvc 0.36.1
  • windows_i686_gnu 0.36.1
  • windows_i686_msvc 0.36.1
  • windows_x86_64_gnu 0.36.1
  • windows_x86_64_msvc 0.36.1
Cargo.toml cargo
  • rstest 0.15 development
  • numpy 0.16
  • pyo3 0.16
  • time 0.3
bench-requirements.txt pypi
  • numpy-financial ==1.
  • scipy ==1.
  • xirr ==0.1.6
dev-requirements.txt pypi
  • maturin ==0.11. development
  • numpy ==1. development
  • numpy-financial ==1. development
  • pandas ==1. development
.github/workflows/bench.yaml actions
  • actions-rs/toolchain v1 composite
  • actions/cache v3 composite
  • actions/checkout v3 composite
  • actions/setup-python v4 composite
  • rhysd/github-action-benchmark v1 composite
.github/workflows/ci.yaml actions
  • actions-rs/toolchain v1 composite
  • actions/cache v3 composite
  • actions/checkout v3 composite
  • actions/download-artifact v3 composite
  • actions/setup-python v4 composite
  • actions/upload-artifact v3 composite
  • messense/maturin-action v1 composite
  • softprops/action-gh-release v1 composite
pyproject.toml pypi