anexen / pyxirr Goto Github PK
View Code? Open in Web Editor NEWRust-powered collection of financial functions.
Home Page: https://anexen.github.io/pyxirr/
License: The Unlicense
Rust-powered collection of financial functions.
Home Page: https://anexen.github.io/pyxirr/
License: The Unlicense
Trying to use keyword silent=True in xnfv but getting keyword not recognized error. Appears to be working in other functions though so wondered if it hasn't been implemented into xnfv yet despite being in documentation. Apologies in advance if this is just a use case issue on my end.
Hi
Pyxirr is really a good package. The performance is really good. When we using irr function, got a weird issue. If we feed 241, 361, or 481 cash flows (including 1 initial loan, and 240,360, and 480 monthly paybacks) to irr function, we got a negative number (-23.848998449508812). Can you please take a look and help us to fix it?
Here is our testing code:
from pyxirr import irr
import numpy_financial as npf
cf = [-172545.848122807] + [787.735232517999] * 480
print(len(cf))
irr_rt= irr(cf)*12
print(irr_rt)
irr_rt = npf.irr(cf)*12
print(irr_rt)
add possibility to set false on error messages when running functions in loop or using Pandas groupby
.. In case of error - no value returned (empty), but it's not affect further workflow execution
Add XFV
function or add description on how it can be calculated using the existing XIRR
and XNPV
I'm trying to install it on an arm linux docker container, running on a M1 macbook host.
On my host it downloads the wheels properly:
% python3 --version
Python 3.10.6
% python3 -m pip install pyxirr --no-cache
Collecting pyxirr
Downloading pyxirr-0.7.2-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (406 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 406.5/406.5 kB 13.2 MB/s eta 0:00:00
Installing collected packages: pyxirr
Successfully installed pyxirr-0.7.2
It installs correctly up to python 3.9:
# python --version
Python 3.9.14
# pip install pyxirr --no-cache
Collecting pyxirr
Downloading pyxirr-0.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (207 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 207.3/207.3 KB 11.1 MB/s eta 0:00:00
Installing collected packages: pyxirr
Successfully installed pyxirr-0.7.2
but fails with python 3.10:
# pip install pyxirr --no-cache
Collecting pyxirr
Downloading pyxirr-0.7.2.tar.gz (128 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 128.7/128.7 kB 10.4 MB/s eta 0:00:00
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... error
error: subprocess-exited-with-error
× Preparing metadata (pyproject.toml) did not run successfully.
│ exit code: 1
╰─> [6 lines of output]
Cargo, the Rust package manager, is not installed or is not on PATH.
This package requires Rust and Cargo to compile extensions. Install it through
the system's package manager or via https://rustup.rs/
Checking for Rust toolchain....
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed
× Encountered error while generating package metadata.
╰─> See above for output.
note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
Having other PE metrics in the same package would be useful for my project (and I'm guessing others?)
I'm thinking of adding DPI, MOIC and Modified IRR as basic metrics and then adding public market equivalent (PME) metrics too (the same metrics but rescaling the PME "cash flows" based on standard methods such as Kaplan Schoar)
For all of these, other than Modified IRR, there would need to be a wrapper on the input data to either separate out positive (distributions) and negative (contributions) cash flows or the two series could be input separately. For Modified IRR, it would just require discount rate and investment rate inputs. For the PMEs the user would need to supply either price or return series for the PME
Also, I'm willing to mock something up that works in python if there is any interest, I just don't have any experience with Rust, so would need help converting it. I already have something in my project, but would need to separate it out to make it clearer
from pyxirr import xirr
from datetime import date
dates = [date(2020, 3, 5), date(2020, 3, 16)]
values = [-18480.0, 13120.0]
print(xirr(dates, values))
None for these dates & amounts:
dates = [date(2021, 6, 9), date(2021, 8, 11)]
amounts = [-134.09, 40.86]
z = sorted(zip(dates, amounts))
print(f'xirr={100.0 * xirr(z):.3f}%')
Excel manages to calculate correctly.
First off, I wanted to say that I LOVE this library. I tested moving from 0.6.4 -> 0.7.2 and it seems like the IRR calcs are somehow twice as fast as they were. So thats incredible. I was hoping that it would reduce None
results as well, but it does not. I was able to come up with ~1700 situations where pyxirr returns None
and numpy financial returns a value. (There were 1707 in 0.6.4 and the same 1707 fail in 0.7.2) NPF is rather slow as you know and it'd be awesome to not have to fallback to NPF at all.
I wanted to get in and see if I could figure out what the issue is but I don't have any r experience - yet.
Here is a file containing the payment info of the ~1700 scenarios
failed-irr.txt
I just had a quick script like this:
import json
from pyxirr import irr
with open("failed-irr.txt", "r") as file_object:
bad_payments_list = json.loads(file_object.read())
fail_count = 0
success_count = 0
for bad_payment in bad_payments_list:
monthly_irr = irr(bad_payment)
if monthly_irr is None:
fail_count += 1
else:
success_count += 1
print('Successful: ', success_count)
print('Failed: ', fail_count)
It takes a bit to run through all 1700 calcs. I realize this is open source and you likely have limited time to look at this. Let me know if theres anything else I can provide to help.
There was something wrong with my dataset. Please delete!
Any chance I can convince you to do a new point release that includes the change on HEAD to upgrade maturin? (I'm trying to import this in a build system that knows about PEP 621 and the updated pyproject.toml would help it automatically figure out dependencies.) Thanks!
It seems that is fine with numpy_financial
:
>>> numpy_financial.ipmt(rate=0.03 / 12, per=numpy.arange(35) + 1, nper=35, pv=10000)
array([-25. , -24.3156167 , -23.62952244, -22.94171294, ...
However, with pyxirr
:
>>> pyxirr.ipmt(rate=0.03 / 12, per=numpy.arange(35) + 1, nper=35, pv=10000)
TypeError: argument 'per': only size-1 arrays can be converted to Python scalars
Not sure if it is related or not, but the returned type when not using an array is also different:
>>> numpy_financial.ipmt(rate=0.03 / 12, per=1, nper=35, pv=10000)
array(-25.)
>>> pyxirr.ipmt(rate=0.03 / 12, per=1, nper=35, pv=10000)
-25
Cant import pyxirr in glue aws
We are getting very different irr values for slightly different cashflows.
cf1
out[16]:
array([-1.44852555e+08, 1.28859998e+06, 1.27305118e+06, 1.25407349e+06,
1.24199669e+06, 1.22647792e+06, 1.21095552e+06, 1.19206955e+06,
1.17989821e+06, 1.16436524e+06, 1.14883185e+06, 1.12945217e+06,
1.11780102e+06, 1.10228427e+06, 1.08671783e+06, 1.06755759e+06,
1.05502327e+06, 1.03885451e+06, 1.02247003e+06, 1.00227444e+06,
9.88024873e+05])
cf2
Out[17]:
array([-1.44852555e+08, 1.41881733e+06, 1.40267049e+06, 1.38296290e+06,
1.37042160e+06, 1.35430596e+06, 1.33818655e+06, 1.31857419e+06,
1.30593472e+06, 1.28980433e+06, 1.27367350e+06, 1.25354845e+06,
1.24144917e+06, 1.22533563e+06, 1.20917048e+06, 1.18927331e+06,
1.17625690e+06, 1.15946627e+06, 1.14245161e+06, 1.12147927e+06,
1.10668164e+06])
pyxirr.irr(cf1), pyxirr.irr(cf2)
Out[19]: (-0.13854127397889382, -1.761587679320197)
# comparison with numpy_financial
npf.irr(cf1), npf.irr(cf2)
Out[18]: (-0.13854127397889426, -0.1320937225730502)
Currently XIRR only works for debt instruments with ACT/ACT conventions. I suggest 30/360, ISMA-30/360 and ACT/360 also be added and be an additional parameter for XIRR function.
It seems they are missing in this package. See:
Currently XIRR calculates IRR (or YTM) for a single date. But it would be awesome if I could provide it (or a different function) with a pd.Series of a bond's or bill's prices across time to calculate XIRR for every point.
For example if we have:
import pandas as pd
prices = pd.Series({
'2020-01-01': 100,
'2020-08-01': 103
})
prices.index = pd.to_datetime(prices.index)
bond_schedule = pd.Series({
'2020-07-01': 10,
'2021-01-01': 110
})
then I would need to create a new arguments for dates and amounts for every date/price, i.e. ['2020-01-01', '2020-07-01'] and [-100, 10, 110] , ['2020-08-01', '2021-01-01'] and [-103, 110]. And it could be that I have not 2, but hundreds of dates. As you can see here, as date/prices grow newer, some of the amounts aren't relevant anymore as well. Would be awesome if it's implemented!
In example:
s = Series(
index=date_range("2021", "2022", freq="MS", closed="left"),
data=[-100] + [20] * 11,
)
xirr(s) # 5.09623547168478
df = DataFrame(
index=date_range("2021", "2022", freq="MS", closed="left"),
data={
"one": [-100] + [20] * 11,
"two": [-80] + [19] * 11,
},
)
xirr(df) # Series(index=["one", "two"], data=[5.09623547168478, 8.780801977141174])
For the DataFrame
I am suggesting returning a Series
type simply because that is what i.e. df.sum()
would return (applying .sum()
to all columns).
Feel free to close if is out of scope for this module! (I would understand that) 😊
We'd like to upgrade our project to Python 3.11 soon, but the version of pyxirr
on PyPI still requires Python <3.11
. It looks like the metadata was updated in #26 to allow 3.11, but a new version was never published (addressed in this comment).
Unfortunately, Poetry refuses to install an incompatible package, so there is no workaround for us beyond removing the library entirely.
Thanks for your work on pyXIRR. I was looking for something with XIRR, but it was a nice surprise to find the PME functionality too.
For the index amounts on the PME functions, would it be possible to include the dates of the cash flows and then automatically fetch the index amounts somehow?
Hello. First of all, I´d like to thank you guys for the awesome library !
I am having an issue while trying to use it, I´ve managed to fix it by manually searching for conflicting dependencies inside pipenv
, which leads me to believe this issue may be related to undeclared dependencies withing the build-system you guys are using on the package !
Here is the issue I face to run the app after installing pyxirr
:
PS C:\codebase\my_path> & C:/Users/myuser/.virtualenvs/my_path-r724wWIu/Scripts/python.exe my_path/main.py
Traceback (most recent call last):
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\_compat.py", line 48, in <module>
from requests.packages.urllib3.contrib import appengine as gaecontrib
ImportError: cannot import name 'appengine' from 'requests.packages.urllib3.contrib' (C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\urllib3\contrib\__init__.py)
from ..util.multipart_stream import MultipartStream
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\boxsdk\util\multipart_stream.py", line 3, in <module>
from requests_toolbelt.multipart.encoder import MultipartEncoder
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\__init__.py", line 12, in <module>
from .adapters import SSLAdapter, SourceAddressAdapter
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\adapters\__init__.py", line 12, in <module>
from .ssl import SSLAdapter
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\adapters\ssl.py", line 16, in <module>
from .._compat import poolmanager
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\_compat.py", line 50, in <module>
from urllib3.contrib import appengine as gaecontrib
ImportError: cannot import name 'appengine' from 'urllib3.contrib' (C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\urllib3\contrib\__init__.py)
steps to reproduce:
boxsdk 1.8-2.2
)Importing InvalidPaymentsError as:
from pyxirr import InvalidPaymentsError
results in an import error being flagged by mypy.
Workaround needed to run is:
from pyxirr import InvalidPaymentsError # type: ignore [attr-defined]
Explicitly declaring the exception name in the .pyi file should solve this issue.
Functions for calculating the payment (pmt
) and periods (nper
) are implemented, but it seems the function for calculating the interest rate is missing:
irr([87.17, 87.17, 87.17, 87.17, 87.17, 87.17, 87.17, 87.17, 87.17, 87.17, 87.17, 87.17, -86.43])
Returns None
numpy_financial returns -0.5020732642263963
for these same values
Similarly if I reverse the signs
irr([-87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, 86.43])
pyxirr's irr returns None
and numpy_financial's IRR (npf.irr) returns -0.5020732642263963
(the same as above)
I'm not 100% sure what the breaking point is, but I have other examples of many more items (up to 180 'deposits') that are returning None from the irr function.
e.g.:
[-87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, -87.17, 5809.3]
Please let me know if I could provide anything else to help troubleshoot!
Thanks for making this library!
Your irr
function is about 15x faster than numpy_financial
on my data.
Would it be possible to add arguments for the convergence-tolerance and max number of iterations for the root-finding algorithm? It seems they have recently added these to numpy_financial
but it is not yet released.
I would like to try and make irr
run even faster by sacrificing some precision of the result, and also to ensure the time-usage is limited and predictable. Because I need to run this on many thousands of arrays of data, as fast as possible, and I only need a few digits of precision.
There also seems to be a problem when the first number of the array is positive but there are negative numbers for some of the future amounts. This example runs 400x slower than normal and does not return a value or raise an exception:
from pyxirr import irr
x = [10.0, 1.0, 2.0, -3.0, 4.0]
irr(x)
I need it to return np.nan
when a result could not be found within the max number of iterations allowed and the error is not within the given tolerance level.
By the way, pyxirr.__version__
is apparently also missing.
I hope you can make these small changes.
Thanks!
Hi,
when I run the following example:
dates = [date(2020,1,9),date(2020,2,12),date(2020,3,2),date(2020,3,13),date(2020,5,11),date(2020,5,11),date(2020,5,11),date(2020,5,11),date(2020,11,3),date(2020,12,29),date(2021,3,26),date(2021,7,21),date(2022,6,16),date(2022,7,6)]
cashflow = [-1200,-1050,-400,-800,1500,1100,2000,450,-2000,2850,-1500,2025,-2000,2635]
xirr(dates, cashflow)
I get an xirr of 3.6894338683170713; the same calculation in excel gives me. a value of 0.0000003%. Seems to be an issue with the function for values very close to zero, any suggestions on how to deal with this?
thanks
Hello. First of all, I´d like to thank you guys for the awesome library !
I am having an issue while trying to use it, I´ve managed to fix it by manually searching for conflicting dependencies inside pipenv
, which leads me to believe this issue may be related to undeclared dependencies withing the build-system you guys are using on the package !
Here is the issue I face to run the app after installing pyxirr
:
PS C:\codebase\my_path> & C:/Users/myuser/.virtualenvs/my_path-r724wWIu/Scripts/python.exe my_path/main.py
Traceback (most recent call last):
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\_compat.py", line 48, in <module>
from requests.packages.urllib3.contrib import appengine as gaecontrib
ImportError: cannot import name 'appengine' from 'requests.packages.urllib3.contrib' (C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\urllib3\contrib\__init__.py)
from ..util.multipart_stream import MultipartStream
File "C:\Users\myuser\.virtualenvsmy_path-r724wWIu\Lib\site-packages\boxsdk\util\multipart_stream.py", line 3, in <module>
from requests_toolbelt.multipart.encoder import MultipartEncoder
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\__init__.py", line 12, in <module>
from .adapters import SSLAdapter, SourceAddressAdapter
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\adapters\__init__.py", line 12, in <module>
from .ssl import SSLAdapter
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\adapters\ssl.py", line 16, in <module>
from .._compat import poolmanager
File "C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\requests_toolbelt\_compat.py", line 50, in <module>
from urllib3.contrib import appengine as gaecontrib
ImportError: cannot import name 'appengine' from 'urllib3.contrib' (C:\Users\myuser\.virtualenvs\my_path-r724wWIu\Lib\site-packages\urllib3\contrib\__init__.py)
steps to reproduce:
boxsdk 1.8-2.2
)on XFV
instead of passing:
rate: Rate, # Rate of interest per period
nper: int, # Number of compounding periods
we can pass:
rate: Rate, # the annual interest rate
start_date: DateLike, # the start date (present "moment")
end_date: DateLike, # the end date (future "moment")
Another (less explicit) option instead of passing start_date
and end_date
is for the function to automatically take them from the series of dates passed (in amounts
or dates
) (start_date
will be the minimum date of this series, end_date
will be the maximum date of this series)
In this case if the user will want to have a start_date
/ end_date
that does not happen on the first/last payment, he/she can add these dates to the series with amount=0
Also, we can add clarifications to the docs on when rate
is per period (e.g. on FV
) and when rate
is the annual interest rate (e.g. on XNPV
)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.