Git Product home page Git Product logo

pyxirr's Introduction

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

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:

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.is_conventional_cash_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.zero_crossing_points(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

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.

from pyxirr import DayCount

xirr(dates, amounts, day_count=DayCount.ACT_360)

# parse day count from string
xirr(dates, amounts, day_count="30E/360")

Private equity performance metrics

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

import pyxirr

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

# Net Present Value
pyxirr.npv(0, [-40_000, 5_000, 8_000, 12_000, 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 array_like, returns values for each input element. If multiple inputs are array_like, performs broadcasting and returns values for each element.

import pyxirr

# feed list
pyxirr.fv([0.05/12, 0.06/12], 10*12, -100, -100)
pyxirr.fv([0.05/12, 0.06/12], [10*12, 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

  • Implement all functions from numpy-financial
  • Improve docs, add more tests
  • Type hints
  • 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).

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

Install dev-requirements

$ pip install -r dev-requirements.txt

Building

$ maturin develop

Testing

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

Benchmarks

$ 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.

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

pyxirr's People

Contributors

amotzop avatar anexen avatar bernardofcordeiro avatar harkylton avatar tijptjik avatar westandskif avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyxirr's Issues

Following input leads to None output

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))

Support Series and DataFrame with DatetimeIndex

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) 😊

IRR function args for tolerance and max iterations

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!

Weird values for xirr when too close to zero

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

Using silent in xnfv

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.

New release?

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!

XIRR for a pd.Series

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!

Fetching PME index amounts

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?

Conflicting sub-dependencies with other libraries

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:

  • with pipenv, try to install pyxirr while having a conflicting package that uses an undeclared dependency. When running the main.py script you will start having these errors due to uncompatible libs (in my case, boxsdk 1.8-2.2)

IRR/XIRR with only two amounts can be solved analytically

In case if amounts contain only 2 items ($CF_0$ and $CF_1$), IRR could be solved using the formula:

$IRR = { (-{CF_1 \over CF_0})^{1/t}-1 }$

It eliminates a need for iterational solving and improves performance.

For example, this python snippet works 5-8 times faster than a call to xirr:

def irr(amount0: float, amount1: float, date0: date, date1: date) -> float:
  return (-amount1/amount0)**(365/(date1-date0).days)-1

High IRR Result

Hello,

First, I would like to express my respect and appreciation for the work you've done on the pyxirr library. It has been immensely helpful in my financial calculations. However, I have encountered an issue that I hope you can assist with.

I am working with the following cash flow array:

cashflow = np.array([0, -54040.55222, -15288.72407, 11947.6118, 13954.22077, 24836.44528, 42522.40517, 32902.24734, 29955.5224, 21873.50073, 20263.8865, 18480.79936, 10197.66285])

However, when using the pyxirr.irr function, the IRR calculated is 55915611079317.1, which seems unusually high.
Here is the code snippet I used:

import numpy as np
import pyxirr

cashflow = np.array([0.0, -54163.55222425675, -15411.724067521238, 11824.611799779348, 13831.220768857136, 24713.445277451923, 42399.405170720645, 32779.24733697434, 29832.522397937253, 21750.50072725094, 20140.886499523196, 18357.799360554745, 10074.662845544659])
irr_result = pyxirr.irr(cashflow)

print(f"The calculated IRR is: {irr_result}")

Could you please advise if I am possibly making an error in my usage?
Thank you for your time and assistance.

`ipmt()` and `ppmt()` do not accept an array as `per`

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

pass start_date (present "moment") and end_date (future "moment") to XFV

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)

Negative IRR

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)

what is different in excel and pyxirr when calculating xirr?

Hello,
I encountered some problems while calculating xirr. Could you please help me check if it is a bug。

This is data file:
3547的irr.xlsx

Firstly, when I use Excel to calculate xirr, I can get the results:
image

But,when I use pyxirr to calculate xirr, I can not get the results, it return None.

code in here:
pyxirr==0.10.3

import openpyxl
from pyxirr import xirr
from decimal import Decimal

wb = openpyxl.load_workbook("3547的irr.xlsx", read_only=True)
sheet = wb["3547的irr"]

header = []

dates = []
cashs = []
values = []

for idx, row in enumerate(sheet.rows):
    value = [x.value for x in row]
    if idx <= 0:
        header = value
        continue
    values.append(dict(zip(header, value)))

values.sort(key=lambda x: x["report_date"])

for v in values:
    if v["dim_id"] != "3547##0":
        continue
    v["report_date"] = v["report_date"].date()
    v["market_value"] = Decimal(v["market_value"])
    dates.append(v["report_date"])
    cashs.append(v["market_value"])
    if not v["between_day"]:
        continue
    if v["between_day"] <= 1:
        dates.append(v["report_date"])
        v["market_value2"] = Decimal(v["market_value2"])
        cashs.append(v["market_value2"])
        # 0
        # step = -4682
        step = 0
        irr = xirr(dates[step:], cashs[step:], guess=-0.9)
        print(irr)

wb.close()

In line 4681 of the file, there is a significant negative value, which may be the reason why it cannot be calculated:
image

But Excel can calculate it, so I want to know where the difference is?

Payment scenarios where IRR returns None

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.

IRR returns none for this set of values

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!

Wrong irr values

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)

add `XFV` function

Add XFV function or add description on how it can be calculated using the existing XIRR and XNPV

Can't install from wheels for 3.10 on arm linux (inside M1 host docker)

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.

Dependency Issue

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:

  • with pipenv, try to install pyxirr while having a conflicting package that uses an undeclared dependency. When running the main.py script you will start having these errors due to uncompatible libs (in my case, boxsdk 1.8-2.2)

Control Xirr accuracy

Hi Sir,

Is there a way i can set a parameter on how many trials i wanna run? I run some cashflows and cross check with excel numbers and there are some ~<1% differences which i believe it's owing to number of trials. / tolerence

Best,
Roger

Interest in adding private equity metrics?

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.