Recursive function for CPI - python

Having a play around trying to better understand recursion. I want to make a function that shows the CPI increase for a particular year given a starting amount.
Assuming the starting amount is 100000 and CPI rate is 5%, then f(0) = 100000, f(1) = 5000, f(2) = 5250 etc.I want to return the CPIincrease column from below
rate 0.05
n TotalCPI CPIincrease
0 100000
1 105000 5000
2 110250 5250
3 115762.5 5512.5
4 121550.625 5788.125
5 127628.1563 6077.53125
6 134009.5641 6381.407812
7 140710.0423 6700.478203
8 147745.5444 7035.502113
9 155132.8216 7387.277219
10 162889.4627 7756.64108
So far I have the TotalCPI from column of the above table
def CPIincreases(n):
if n<=0:
return initial
else:
return (CPIincreases(n-1))*(1+CPIrate)
initial = 100000
CPIrate = 0.05
print(CPIincreases(1),CPIincreases(2),CPIincreases(3),CPIincreases(4))
output: 105000.0 110250.0 115762.5 121550.625
Now I'm lost. Because the output shows the I should be adding in
CPIincrease(n) - CPIincrease(n-1)
Somewhere.
Any Help greatly appreciated, even if its to say this function is not possible.
Cheers

The function you have created calculates the total value of the lump sum over time, and as you have pointed out, you can call it twice (once with year and once with year - 1) and take the difference to get your answer.
If you really want do this recursively in one go we need to think through the base cases:
Year 0: At the beginning there is no interest
return 0
Year 1: After the first year the change is just the initial amount times the interest rate
return initial * rate
Year 2+: From this year on, we make the same as last year, plus the interest on that interest
return last_year + rate * last_year
Or just: return last_year * (1 + rate)
Now we can put it all together:
def cpi_increase(year, initial, rate):
if year == 0:
return 0
if year == 1:
return initial * rate
return (1 + rate) * cpi_increase(year - 1, initial, rate)
If we print this out we can see the values about match up:
initial = 100000
rate = 0.05
for year in range(11):
print('{year:<5} {total:<21} {cpi_increase}'.format(
year=year,
total=initial * (1 + rate) ** year,
cpi_increase=cpi_increase(year, initial, rate)
))
The values:
0 100000.0 0
1 105000.0 5000.0
2 110250.0 5250.0
3 115762.50000000001 5512.5
4 121550.62500000003 5788.125
5 127628.15625000003 6077.53125
6 134009.56406250005 6381.407812500001
7 140710.04226562506 6700.478203125001
8 147745.5443789063 7035.502113281251
9 155132.8215978516 7387.2772189453135
10 162889.4626777442 7756.64107989258
Thinking through our base cases also shows how to create the direct calculation. At year y we have applied the (1 + rate) multiplication y - 1 times and the base (initial * rate) once. This gives us:
def cpi_increase_direct(year, initial, rate):
if year <= 0:
return 0
return initial * rate * (1 + rate) ** (year - 1)

I like how Jon's answers is more elaborate. Here's my code, I've tried to make variable names self explanatory but I'll briefly describe them as well.
total_cpi: first column
cpi_increase: 2nd column
cpi_rate: CPIrate
If we need to solve it in one recursive function, we can solve this problem only by using state variables:-
def calculate_cpi_increase(total_cpi, cpi_increase, year):
if year == 0:
return total_cpi, cpi_increase
else:
return calculate_cpi_increase(total_cpi*(1+cpi_rate), total_cpi*cpi_rate, year-1)
cpi_rate = 0.05
calculate_cpi_increase(100000, 0, 10)
result: (162889.46267774416, 7756.641079892579)

First of all you should not call a recursive function with all the values that you want to print. For example if you call F(2),F(3),F(4) and F(5) you would repeat the calculations for F(2) 4 times, as every other call needs this calculation.
You should not use global variables also, you can use my simple approach and encapsulate them in another function. In this code I generate not only one value, this generates the full table, a list of python tuples. Any tuple are two values, the value and the increment per iteration. The full table is printed by another function.
def CPITable(n, initial = 100000, CPIrate = 0.05):
def CPITableRecurse(n):
if n<=0:
return [(initial,0)]
else:
CPI = CPITable(n-1)
inc = CPI[-1][0] * CPIrate
CPI.append((CPI[-1][0] + inc , inc ))
return CPI
return CPITableRecurse(n)
def printTable(table):
i = 0
for line in table:
print ( str(i) + " %5.2f %5.2f" % line)
i += 1
printTable(CPITable(6))
#output:
# 0 100000.00 0.00
# 1 105000.00 5000.00
# 2 110250.00 5250.00
# 3 115762.50 5512.50
# 4 121550.62 5788.12
# 5 127628.16 6077.53
# 6 134009.56 6381.41

Related

How to loop in python to target amount?

I'm having difficulty with the below problems and not sure what I'm doing wrong. My goal is to figure out how many periods I need to compound interest on a deposit using loops to reach a target deposit amount on a function that takes three arguments I have to create. I've included what I have below but can't seem to get my number of periods.
Example:
period(1000, .05, 2000) - answer 15
where d is initial deposit, r is interest rate and t is target amount.
new_deposit = 0
def periods (d,r,t):
while d*(1+r)<=t:
new_deposit = d*(1+r) - d
print(new_deposit)
return periods
I'm very new to this so not sure where I'm going wrong.
You were close, but your return statement would throw an error as you never set periods.
def periods(d,r,t):
count_periods = 1
current_ammount = d
while current_ammount*(1+r)<=t:
current_ammount = current_ammount*(1+r)
count_periods+=1
print(current_ammount)
return count_periods
print(periods(100, 0.01, 105))
I renamed the return variable, as to not overlap with the function name itself.
EDIT: sorry your logic was flawed all the way through the code, rewrote it.
def periods(d, r, t):
p = 0
while d < t:
d *= (1 + r)
p += 1
return p
periods(100, .01, 105) # 5

expectation and variance of future stock price under binary tree

Probably a over-simplified model for stock price: on each day, the price will go up by a factor 1.05 with probability 0.6 or will go down to 1/1.05 with probability 0.4. So this is a non-symmetrical binary tree. How can I analytically calculate the expectation and variance of this stock price on future date, say day 100. Also, is there any module in python to handle binary tree model like this? appreciate code to implement this.
Best regards
import random as r
s = 100 # starting value
^^Initial conditions. Simulating one day on the stock market:
def day(stock_value): #One day in the stock market
k = r.uniform(0,1)
if k < 0.6:
output = 1.05*stock_value
else:
output = stock_value/1.05
return(output)
Simulating 100 days on the stock market:
for j in range(100): #simulates 100 days in the stock market
s = day(s)
print(s)
Simulating 100 days 1000 times:
data = []
for i in range(1000):
s = [100]
for j in range(100):
s.append(day(s[j]))
data.append(s)
Converting the data to only consider the last day:
def mnnm(mat): #Makes an mxn matrix into an nxm matrix
out = []
for j in range(len(mat[0])):
out.append([])
for j in range(len(mat[0])):
for m in range(len(mat)):
out[j].append(mat[m][j])
return(out)
data = mnnm(data)
data = data[-1]
Taking a mean average:
def lst_avg(lst): #Returns the average of a list
output = 0
for j in range(len(lst)):
output+= lst[j]/len(lst)
return(output)
mean = lst_avg(data)
Variance:
import numpy as np
for h in range(len(data)):
data[h] = data[h]**2
mean_square = lst_avg(data)
variance = np.fabs(mean_square - mean**2)
The theoretical value after 1 day is (assuming value on day 0 is A)
A * 0.6 * 1.05 + 100 * 0.4/1.05
And after 100 days it's
A * (0.603 + 0.380952...)**100 so...
(in the following I use 1 as stock price on day 0.)
p1 = 0.6
p2 = 0.4
x1 = 1.05
x2 = 1/1.05
initial_value = 1
no_of_days = 100
# 1 day
expected_value_after_1_day = initial_value * ( p1*x1 + p2*x2)
print (expected_value_after_1_day, 'is the expected value of price after 1 day')
ex_squared_value_1_day = initial_value * (p1*x1**2 + p2*x2**2)
# variance can be calculated as follows
variance_day_1 = ex_squared_value_1_day - expected_value_after_1_day**2
# or an alternative calculation, summing the squares of the differences from the mean
alt_variance_day_1 = p1 * (x1 - expected_value_after_1_day) ** 2 + p2 * (x2 - expected_value_after_1_day) ** 2
print ('Variance after one day is', variance_day_1)
# 100 days
expected_value_n_days = initial_value * (p1*x1 + p2*x2) ** no_of_days
ex_squared_value_n_days = initial_value * (p1*x1**2 + p2*x2**2) ** no_of_days
ex_value_n_days_squared = expected_value_n_days ** 2
variance_n_days = ex_squared_value_n_days - ex_value_n_days_squared
print(expected_value_n_days, 'is the expected value of price after {} days'.format(no_of_days))
print(ex_squared_value_n_days, 'is the expected value of the square of the price after {} days'.format(no_of_days))
print(ex_value_n_days_squared, 'is the square of the expected value of the price after {} days'.format(no_of_days))
print(variance_n_days, 'is the variance after {} days'.format(no_of_days))
It probably looks a bit old-school, hope you don't mind!
Output
1.0109523809523808 is the expected value of price after 1 day
Variance after one day is 0.0022870748299321786
2.972144657651404 is the expected value of price after 100 days
11.046309656223373 is the expected value of the square of the price after 100 days
8.833643866005783 is the square of the expected value of the price after 100 days
2.2126657902175904 is the variance after 100 days

Calculating monthly growth percentage from cumulative total growth

I am trying to calculate a constant for month-to-month growth rate from an annual growth rate (goal) in Python.
My question has arithmetic similarities to this question, but was not completely answered.
For example, if total annual sales for 2018 are $5,600,000.00 and I have an expected 30% increase for the next year, I would expect total annual sales for 2019 to be $7,280,000.00.
BV_2018 = 5600000.00
Annual_GR = 0.3
EV_2019 = (BV * 0.3) + BV
I am using the last month of 2018 to forecast the first month of 2019
Last_Month_2018 = 522000.00
Month_01_2019 = (Last_Month_2018 * CONSTANT) + Last_Month_2018
For the second month of 2019 I would use
Month_02_2019 = (Month_01_2019 * CONSTANT) + Month_01_2019
...and so on and so forth
The cumulative sum of Month_01_2019 through Month_12_2019 needs to be equal to EV_2019.
Does anyone know how to go about calculating the constant in Python? I am familiar with the np.cumsum function, so that part is not an issue. My problem is I cannot solve for the constant I need.
Thank you in advance and please do not hesitate to ask for further clarification.
More clarification:
# get beginning value (BV)
BV = 522000.00
# get desired end value (EV)
EV = 7280000.00
We are trying to get from BV to EV (which is a cumulative sum) by calculating the cumulative sum of the [12] monthly totals. Each monthly total will have a % increase from the previous month that is constant across months. It is this % increase that I want to solve for.
Keep in mind, BV is the last month of the previous year. It is from BV that our forecast (i.e., Months 1 through 12) will be calculated. So, I'm thinking that it makes sense to go from BV to the EV plus the BV. Then, just remove BV and its value from the list, giving us EV as the cumulative total of Months 1 through 12.
I imagine using this constant in a function like this:
def supplier_forecast_calculator(sales_at_cost_prior_year, sales_at_cost_prior_month, year_pct_growth_expected):
"""
Calculates monthly supplier forecast
Example:
monthly_forecast = supplier_forecast_calculator(sales_at_cost_prior_year = 5600000,
sales_at_cost_prior_month = 522000,
year_pct_growth_expected = 0.30)
monthly_forecast.all_metrics
"""
# get monthly growth rate
monthly_growth_expected = CONSTANT
# get first month sales at cost
month1_sales_at_cost = (sales_at_cost_prior_month*monthly_growth_expected)+sales_at_cost_prior_month
# instantiate lists
month_list = ['Month 1'] # for months
sales_at_cost_list = [month1_sales_at_cost] # for sales at cost
# start loop
for i in list(range(2,13)):
# Append month to list
month_list.append(str('Month ') + str(i))
# get sales at cost and append to list
month1_sales_at_cost = (month1_sales_at_cost*monthly_growth_expected)+month1_sales_at_cost
# append month1_sales_at_cost to sales at cost list
sales_at_cost_list.append(month1_sales_at_cost)
# add total to the end of month_list
month_list.insert(len(month_list), 'Total')
# add the total to the end of sales_at_cost_list
sales_at_cost_list.insert(len(sales_at_cost_list), np.sum(sales_at_cost_list))
# put the metrics into a df
all_metrics = pd.DataFrame({'Month': month_list,
'Sales at Cost': sales_at_cost_list}).round(2)
# return the df
return all_metrics
Let r = 1 + monthly_rate. Then, the problem we are trying to solve is
r + ... + r**12 = EV/BV. We can use numpy to get the numeric solution. This should be relatively fast in practice. We are solving a polynomial r + ... + r**12 - EV/BV = 0 and recovering monthly rate from r. There will twelve complex roots, but only one real positive one - which is what we want.
import numpy as np
# get beginning value (BV)
BV = 522000.00
# get desired end value (EV)
EV = 7280000.00
def get_monthly(BV, EV):
coefs = np.ones(13)
coefs[-1] -= EV / BV + 1
# there will be a unique positive real root
roots = np.roots(coefs)
return roots[(roots.imag == 0) & (roots.real > 0)][0].real - 1
rate = get_monthly(BV, EV)
print(rate)
# 0.022913299846925694
Some comments:
roots.imag == 0 may be problematic in some cases since roots uses a numeric algorithm. As an alternative, we can pick a root with the least imaginary part (in absolute value) among all roots with a positive real part.
We can use the same method to get rates for other time intervals. For example, for weekly rates, we can replace 13 == 12 + 1 with 52 + 1.
The above polynomial has a solution by radicals, as outlined here.
Update on performance. We could also frame this as a fixed point problem, i.e. to look for a fixed point of a function
x = EV/BV * x ** 13 - EV/BV + 1
The fix point x will be equal to (1 + rate)**13.
The following pure-Python implementation is roughly four times faster than the above numpy version on my machine.
def get_monthly_fix(BV, EV, periods=12):
ratio = EV / BV
r = guess = ratio
while True:
r = ratio * r ** (1 / periods) - ratio + 1
if abs(r - guess) < TOLERANCE:
return r ** (1 / periods) - 1
guess = r
We can make this run even faster with a help of numba.jit.
I am not sure if this works (tell me if it doesn't) but try this.
def get_value(start, end, times, trials=100, _amount=None, _last=-1, _increase=None):
#don't call with _amount, _last, or _increase! Only start, end and times
if _amount is None:
_amount = start / times
if _increase is None:
_increase = start / times
attempt = 1
for n in range(times):
attempt = (attempt * _amount) + attempt
if attempt > end:
if _last != 0:
_increase /= 2
_last = 0
_amount -= _increase
elif attempt < end:
if _last != 1:
_increase /= 2
_last = 1
_amount += _increase
else:
return _amount
if trials <= 0:
return _amount
return get_value(start, end, times, trials=trials-1,
_amount=_amount, _last=_last, _increase=_increase)
Tell me if it works.
Used like this:
get_value(522000.00, 7280000.00, 12)

Fixed Depreciation Table For Each Year in Python

I'm making a Fixed Depreciation table based off the formula:
Fixed rate = 1 - ((salvage / cost) ^ (1 / life))
I have this piece of code so far:
def FixedRateDepreciationTable(salvage,cost, life):
rate = 1 - ((salvage / cost) ** (1 / life))
print("Year Depreciation Book Value at the year-end")
dv= cost * rate
cost= cost - dv
print("{0:4} {1:>18} {2:26}".format(1,"$"+str(round(dv,2)),cost))
FixedRateDepreciationTable(1000, 100000, 10)
Which gives the result:
Year Depreciation Book Value at the year-end
1 $36904.27 63095.73444801933
I'm unsure how to get the rest of the years to print out along with the first year. How can I get all the years to print out with the Depreciation and Book Value using the code I have now?
I'm not sure if I've got the formula for depreciation right (I've been taught different formulas to the one you give) but you can adapt this logic if necessary.
Essentially what I'm doing is turning FixedRateDepreciationTable into a generator function so that it will yield the depreciation and new value for each year, up until the end of the product's usable life.
In the main body of code, I iterate over this generator and print each value.
def FixedRateDepreciationTable(salvage, cost, life):
rate = 1 - ((salvage / cost) ** (1 / life))
for year in range(1, life + 1):
dv = cost * rate
cost -= dv
yield year, round(dv, 2), cost
if __name__ == '__main__':
print("Year\tDepreciation\tBook Value at the year-end")
for year, depreciation, new_value in FixedRateDepreciationTable(1000, 100000, 10):
print("{0:4}\t{1:>18}\t{2:26}".format(year, depreciation, new_value))
Output
Year Depreciation Book Value at the year-end
1 36904.27 63095.73444801933
2 23285.02 39810.71705534973
3 14691.85 25118.8643150958
4 9269.93 15848.931924611135
5 5848.93 10000.0
6 3690.43 6309.573444801932
7 2328.5 3981.0717055349724
8 1469.19 2511.88643150958
9 926.99 1584.8931924611134
10 584.89 999.9999999999999
Use a loop:
for year in range(1, life):
Indent the lines of code to put them in the loop.

Returning multiple values from function in python 3.5 [duplicate]

This question already has answers here:
How can I return two values from a function in Python?
(8 answers)
Closed 6 years ago.
I'm trying to get some help in returning values from "year_calc" function below (Python 3.5). In essence, the code works for returning "b" as I need a new starting value for "b" to be passed to "year_calc" for each iteration - I can get that to work just fine. However, I want the "total_cost" value from each year_calc iteration to be returned and added up until finished. Note the "grand_total" under the while loop. I realize this doesn't work as stated - just adding it so it may add clarity to what I'm attempting to accomplish. I am just not sure how to pull a specific value which is being returned. Any insight?
def main():
archive_total = float(input('Enter archive total (GB): '))
transfer_rate = float(input('Enter transfer rate (Gbps): '))
days_to_transfer = ((((archive_total*8/transfer_rate)/60)/60)/24)
xfer_per_day = archive_total/days_to_transfer
day_cost = xfer_per_day * 0.007 / 30
days = 365
total_days = 0
sum = 0
b = xfer_per_day * 0.007 / 30
total_years = 1
grand_total = 0.0
total_cost = 0.0
while total_years < years_to_transfer + 1:
b = year_calc(day_cost, days, total_days, sum,b,total_years,total_cost)
total_years += 1
grand_total += total_cost
def year_calc(day_cost,days,total_days,sum,b,total_years,total_cost):
while total_days < days -1:
b += day_cost
sum += b
total_days += 1
total_cost = sum + day_cost
print('Year',total_years,'cost: $', format(sum + day_cost, ',.2f'))
return (b, total_cost)
main()
year_calc, as with any function that returns multiple items, will return its values in a tuple. Therefore, you can just change this line:
b = year_calc(day_cost, days, total_days, sum,b,total_years,total_cost)
to this one:
b, total_cost = year_calc(day_cost, days, total_days, sum,b,total_years)
This works because of how Python handles multiple assignment:
>> a, b = 1,2
>> print a
1
>> print b
2
As an aside, you should try to avoid using builtin names like sum for your variables. And I'm not sure what years_to_transfer is - do you define that elsewhere in your code?
If I understand correctly your description correctly, this implements what you want:
def main():
# ...
total_cost = 0.0
while total_years < years_to_transfer + 1:
b, total_cost = year_calc(day_cost, days, total_days, sum,b,total_years,total_cost)
# ...
def year_calc(day_cost,days,total_days,sum,b,total_years,total_cost):
# ...
return (b, total_cost)
main()
Hmm, seems a bit like trying to code VBA in Python... :-)
Ok, first: I don't think you want to pass total_cost to the function year_calc, as you do not depend on any value you get. So remove it from the definition line:
def year_calc(day_cost,days,total_days,sum,b,total_years):
...
Next: you calculate a new value for total_cost and return a tupple from the function. That's pretty correct.
Now, when callin year_calc you should remove the total_cost variable from calling the function. But you should remember that you return a tupple, so assign the value to a tupple:
(b, total_cost) = year_calc(day_cost, days, total_days, sum,b,total_years)
Bottom line: there are no ref variables (or output variables, ...) to be sent in a function in python. Put in the parameters, nothing more. If you want to return 2 different calculations, return a tupple, but assign the value also to a tupple. Much cleaner.

Categories