fsolve is a SciPy root-finding function that numerically searches for a value making an equation f(x) equal to zero. In financial calculations, that value can be an internal rate of return or a pretax withdrawal amount. section 7.1.2 section 9.2.2
Solving for a dollar-weighted return
Define the cash-flow equation, then call fsolve with the function and an initial estimate: root = fsolve(f, 0). For cash flows of 10, 10, and -19.8, the solution is approximately -0.0066, or -0.66%. section 7.1.2
A generalized financial root-finding function can:
- Accept arbitrary cash flows and dates through extra arguments passed with args=(cashflows, dates). section 7.1.2
- Convert YYYY-mm-dd strings to datetime objects and discount each cash flow according to elapsed days. section 7.1.2
- Solve tax gross-up equations by returning gross withdrawal minus calculated tax minus desired net spending. section 9.2.2
Listing 7.1 Solving for a dollar-weighted return
from scipy.optimize import fsolve
def f(x):
return 10+10/(1+x)-19.8/(1+x)**2
root = fsolve(f, 0)
print('The Dollar-Weighted Return is ', root.item()) #1
> The Dollar-Weighted Return is -0.0066
Use the compact listing to see the minimum fsolve call for an internal-rate-of-return calculation. section 7.1.2
Listing 7.2 General solution for the dollar-weighted return
from datetime import datetime
cashflows = [10, 10, -19.8]
dates = ['2020-01-01', '2021-01-01', '2022-01-01']
dates = [datetime.strptime(dt, '%Y-%m-%d') for dt in dates] #1
def f(x, *args):
cashflows, dates = args
sumPVs = 0
for i in range(len(cashflows)):
Y = (dates[i] - dates[0]).days/365 #2
sumPVs += cashflows[i]/(1+x)**Y
return sumPVs
root = fsolve(f, 0, args=(cashflows, dates)) #3
print('The Dollar-Weighted Return is ', root.item())
Use the generalized listing to inspect date handling, arbitrary cash flows, and argument passing. section 7.1.2
Listing 9.3 Solving for the required pretax withdrawal amount
from scipy.optimize import fsolve
def gross_up(gross, net, TaxTable, deduction):
tax = calc_taxes(gross, TaxTable, deduction)
return gross - tax - net
root = fsolve(gross_up, 0, args=(120000, TaxTable, 13850))
print('The pre-tax withdrawal amount is ', root.item())
Use the tax-withdrawal listing to see fsolve applied to a nonlinear after-tax spending constraint. section 9.2.2
