Time Value of Money NumPy Functions, Working with Varying Floating Rates - python

I would like to ask about the NumPy functions such as NumPy.fv(). I am aware of how to execute this function but ONLY for interest rates that are fixed. I would like to ask what if the rates are floating/varying interest rate?
For example,
ABC deposited $1,000,000 into a bank, the bank pays a floating rate annually as shown:
[1.2%, 1%, 1.8%, 1.2%, 0.9%]. What is the total amount ABC will receive after 5 years?
What I understand is through the use of for-loops and I know how to work this out via Excel but I have been scratching my head around this if the TVM functions may be implemented inside this for-loop to work out the final compounded amount after 5 years?

I don't think you really need anything complicated for this:
principal = 1000000
rates = [0.012, 0.01, 0.018, 0.012, 0.009]
for r in rates:
principal = principal*(1+r)
print("${:,.2f}".format(principal))
Output:
$1,062,481.42

Related

Percentage breakdown 1-100 rating question data (1 Strongly Disagree - 100 Strongly Agree)

I want to know what percentage of people that agree or strongly agree with a 1-100 rating scale in Python. I can use .describe() but it won't tell me what percentage of people chose 60 or higher.
The question is a statement and respondents must click 1 (Strongly Disagree) to 100 (Strongly Agree).
How do I get the percentage breakdown for respondents that said 60 or higher?
Thank you!
One simple way to do this is to make a new column and take the mean:
Q2['newcol'] = Q2['I fully enjoy ...'] >= 60
print(Q2['newcol'].mean())
That should give you the correct fraction.
The idea here is that we translate the response into a 0 or 1 binary value; the mean of this data is then the sum of those values divided by the count, which is equal to the number of 1s divided by the count, i.e. the fraction of people who gave a matching (i.e., >= 60) answer.

Rounding rules for itemized calculations

After pouring over several stackoverflow posts and many many websites, I am resorting to directly asking this question from the smarter folks here. Our platform deals with currency calculations for taxes, discounts, etc. We are currently focused on USD and CAD only. We are a pretty standard shop that is running our backend services on python and on the frontend, we have a few apps on iOS and Andriod.
We do all our calculations in our backend and we use python's decimal for all our calculations and we quantize right before showing the values in our UI or actually processing payments. Our initial pricing is normal in cents and integers but can end up with values of upto 4 decimal places. This is where it gets interesting.
Here is a basic example:
*** These values are calculated in the backed ***
[1a] Price of item (in dollars): $3.75
[1b] Price of item (in cents): 375
[1c] Tax rate: 6.25%
[1d] Calculated tax (in cents): 23.4375 ( = 375 * 6.25%)
[1e] Tip: 15%
[1f] Calculated tip (in cents): 56.2500 ( = 375 * 15%)
[1g] Total (in cents): 454.6875 ( = 375 + 23.4375 + 56.2500)
[1h] Total (in dollars and rounded): $4.55
*** This is visible to user ***
[2a] Price of item (in dollars): $3.75
// Value for [2b] is taken and rounded from value of [1d]
[2b] Tax (in dollars and rounded): $0.23
// Value for [2c] is taken and rounded from value of [1f]
[2c] Tip (in dollars and rounded): $0.56
// Value for [2d] is taken and rounded from value of [1g]
[2d] Total (in dollars and rounded): $4.55
However, if you add [2a], [2b] and [2c], you get:
[2e] 3.75 + 0.23 + 0.56 = 4.54
As you can see [2e] and [1h] are off by a cent.
What is the best way to calculate and display currency amounts.
In general, if you want to sum-then-round on the backend, you want to display rounded line-items, and you want the rounded line items to add up to the same total, then at least one of the line items might have to be rounded incorrectly by up to a penny. Your only option is to break at least one of those requirements. Some possible ways to do that (which you should run by a lawyer familiar with your jurisdiction/business) include:
Adjust the backend code. I'd personally find it a bit surprising if, e.g., a 15% tip weren't rounded to the nearest cent even as a line item.
Don't display some of the line items (or, e.g., group the Tax and Tip into a single line so that when grouped the sum-then-round and round-then-sum strategies match)
Just use the frontend total rather than the backend total, eating the <=$0.005 loss as a business to avoid customer service issues.
Display extra precision to the end user.
Include a footnote/FAQ to educate the user about a potential discrepency.
Adjusting some of the line items to include the missing pennies.

Bisect Search to choose best savings rate

Hi I would like some help with this questions set as one of the problems on the MIT OCW Computer Science and Python Course. I know people have asked similar questions and I have found useful posts such as Bisection search code doesnt work but I am still stuck!
I have struggled with this problem for many days and tried to tackle it in different ways and failed in all ways. If at all possible, could somebody just hint at where I am going wrong, rather than telling me the answer. I would like to solve this problem for myself with bit of help.
For reference, the question is part C, here: https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/assignments/MIT6_0001F16_ps1.pdf
As I have been struggling, I have broken down this task into an overall aim and then into steps to solve the problem.
Aim: try to find the best rate of savings to achieve a down payment on a $1M house in 36 months ##Steps to solve the problem:
1) make a guess on the savings rate, which is the average of the 0 and 1000
2) calculate how that would grow over 36 months
3a) if amount reached goes over 25% of $1m within 36 months, then a lower savings rate should be the new guess
...max=guess (old guess) and min=0 and update the guess (average of high and low)
...run the calculation in step 2 with the new guess
3b) if amount does not reach 25% of $1m within 36 months, then a higher savings rate should be the new guess
...min=guess (old guess) and update the guess (average of high and low)
...run the calculation in step 2 with the new guess
3c) if amount reaches 25% of $1m within the 36th month deadline then quit and record the savings rate as the best guess.
For simplicity: assume no interest and assume wages remain same
So here's my code with the current effort at solving this. (it leads to the "guess" variable tending to 0 and then infinitely looping)
total_cost=1000000 #cost of house
portion_down_payment=0.25 #fraction of cost needed for downpayment on house
downpayment=total_cost*portion_down_payment
starting_annual_salary=float(input("Enter the starting salary: "))
low=0
high=1000
bisect_steps=0
month=1 #set as 1 because the first calculation will occur in month 1
guess=(low+high)//2
current_savings=0
def calSavings(current_savings,monthly_salary,guess,month):
while month<37:
monthly_savings=monthly_salary*(guess/1000)
current_savings+=monthly_savings
month+=1
return(current_savings)
current_savings=calSavings(current_savings,monthly_salary,guess,1)
while True:
current_savings=calSavings(current_savings,monthly_salary,guess,1)
if current_savings>downpayment and month<=35: #if amount reached goes over 25% of $1m within 36 months
#a lower savings rate should be the new guess
high=guess #max=guess (old guess) and min=0 and update the guess
bisect_steps+=1
guess=(low+high)//2
print("The guess was too high, so the new lower guess is",guess," This is bisect step",bisect_steps)
continue #send new guess up to beginning of while loop to calculate
elif current_savings<downpayment and month>=36: #if amount does not reach 25% of $1m within 36 months
low=guess
bisect_steps=+1
guess=(low+high)//2
print("The guess was too low, so the new higher guess is",guess," This is bisect step",bisect_steps)
continue #send new guess up to beginning of while loop to calculate
elif current_savings>=downpayment and month==36: #if amount reaches 25% of $1m in the 36th months then quit
# record the savings rate as the best guess
print("The best savings rate is ",guess/100,"%, the amount saved was ",current_savings," in ",month," months")
break #break out of while loop
I know other people have asked similar questions (I have looked at those answers and still not solved my problem) but more than an answer I want help on HOW to solve this problem.
Update
The reason why your loop isn't stopping is because you aren't giving it enough time. What you are forgetting is that you're dealing with the decimal type. Using the == with decimal values is always dangerous. The decimal type is accurate (by default) to 28 places, which means you're trying to find an extremely good approximation for this problem, because only when it's correct to 28 decimals will (current_savings>downpayment or current_savings<downpayment) evaluate to False invoking your exit condition.
Basically, the issue that's causing your problem is that even when you eventually get the estimate of $1,000,000.0000000001, python says this is not equal to $1,000,000.0000000000, so it keeps going until it gets the next 0, but then it just adds another zero and so on. This will continue for a very very long time and in rare cases might never stop due to the fact that not all decimal numbers can be stored as binary numbers (1,000,000 is not among those cases).
So, how do we solve this? There are two options. The easiest one is to ignore cents and just cast your comparison values to int, this will make sure that any value off by a fraction of a dollar will be accepted. The other options is to create a range of accepted answers. Say for example, I'd like to save EXACTLY $1 million in those 36 months, but that isn't likely to happen. So, instead, I'll settle for any amount in the range $1,000,000.00 - $1,000,010.00 (for example). This way, we ensure that any guess that is way too high will get rejected and only a very limited amount of guesses are accepted.
Regardless of which route you go, it is generally a good idea to put the exit condition of an infinite loop to the top, this way you guarantee that it will always be evaluated.
My suggestion would be to write a function like this and use that for your condition to exit the loop (which you would place at the top):
def are_decimals_equal(a, b):
accuracy = 0.0001
return abs(a-b) < accuracy
This will consider 0.00009 (and all decimals less than that) to be equal to 0.0000.
Original
First off, just as a note, what you're doing is not called bisection, it's called binary search.
Now to the problem, you are never altering the value of month in your main loop. This means, as soon as current_savings>downpayment evaluates to False, your program will go into an infinite loop as none of the conditions after it could evaluate to True as month>=36 will always be False.
From what I can see, the second part of your conditions in the if/elif statements is unnecessary, your calSavings will always compute 36 months worth of savings, never more, never less. Thus, if you remove that condition from your if/elif statements, your program will eventually stop and at that point it should settle on the correct answer.
Lastly, the reason why you're seeing 0 as the output is your division at the end. If you do print(typeof(guess)) you will see it is an integer, 100 is also an integer, thus this division will result in some value like 0.3123 which will get truncated to 0. Change your output to float(guess/100) and this will go away.
I hope it's okay for me to provide an answer to my own question here - though it's not a perfect answer.
The results the code produces seem plausible.
total_cost=1000000 #cost of house
portion_down_payment=0.25 #fraction of cost needed for downpayment on house
downpayment=total_cost*portion_down_payment
starting_annual_salary=float(input("Enter the starting salary: "))
monthly_salary=starting_annual_salary/12
low=0
high=1000
binary=0
month=1 #set as 1 because the first calculation will occur in month 1
guess=(low+high)//2
current_savings=0
tolerance=500
def calSavings(current_savings,monthly_salary,guess,month):
while month<37:
monthly_savings=int(monthly_salary*(guess/1000))
current_savings+=monthly_savings
month+=1
return(current_savings)
current_savings=calSavings(current_savings,monthly_salary,guess,1)
while True:
if abs(current_savings-downpayment)<=tolerance: #if the difference between the current savings and downpayment is less than $500
# record the savings rate as the best guess
print("The best savings rate is ",guess/10,"%, the amount saved was $",current_savings," in 36 months")
break #break out of while loop
elif (current_savings-downpayment)>tolerance: #if amount reached goes over 25% of $1m within 36 months
#a lower savings rate should be the new guess
high=guess #high=guess (old guess) and low=low (stays same) and update the guess
binary=binary+1
guess=(low+high)//2
print("The guess was too high, so the new lower savings rate is",guess/10,"%. This is binary-search step",binary)
current_savings=calSavings(0,monthly_salary,guess,1)
continue #send new guess up to beginning of while loop to check if conditionals
elif (downpayment-current_savings)>tolerance: #if amount does not come to within tolerance amount of 25% of $1m within 36 months
low=guess #to make the guess higher, make low=guess (old guess) and high stay the same
binary=binary+1
guess=(low+high)//2
print("guess is ",guess)
if guess>=990: #check if the savings rate guess is getting too high
print("Your wages are too low. You can't save up enough")
break #exit the while loop because conditions will never be met
print("The guess was too low, so the new higher savings rate is",guess/10,"%. This is binary-search step",binary)
current_savings=calSavings(0,monthly_salary,guess,1)
continue #send new guess up to beginning of while loop to check over the conditionals
The tolerance for an acceptable answer is within $500, but if I lower that to $50, I end up in a seemingly infinite loop again, where the guess and the low end up being the same. I am happy that I've made some apparent progress, but baffled that I can't lower the tolerance without it going haywire again.
BTW, I didn't want to seem like I ignored Nick's comments about making the variables into floats, but I explained why I worked in integers in my comment - does that seem correct?

How can I find out the number of outputs in a loop?

I am a beginner at python and I'm struggling with one of my (simple) college assignments. I have been given the following instructions:
A bank is offering a savings account where a yearly fee is charged. Write
a program that lets the user enter
An initial investment.
The yearly interest rate in percent.
The yearly fee.
the program should then calculate the time it takes
for the investment to double. The interest is added on once per year.
An example run of the program:
Enter the investment: 1000
Enter the interest rate: 10
Enter the fee: 10
The investment doubles after 7 years.
I have formulated the following code but am receiving an error message with regards to t. I would really appreciate if I could get some help, thanks!:
t=0
p=float(input("Enter the investment:"))
a=float(input("Enter the interest rate:"))
m=float(input("Enter the fee:"))
i=(float(a/100))
f=p
while f<=(2*p):
f=(float(f*((1+i)**t)-m)
t=t+1
print("The investment doubles after",t,"years")
I tried to write this in a way that was very easy to follow and understand. I edited it with comments to explain what is happening line by line. I would recommend using more descriptive variables. t/p/a/m/f may make a lot of sense to you, but going back to this program 6 months from now, you may have issues trying to understand what you were trying to accomplish. NOTE You should use input instead of raw_input in my example if using Python 3+. I use 2.7 so I use raw_input.
#first we define our main function
def main():
#investment is a variable equal to user input. it is converted to a float so that the user may enter numbers with decimal places for cents
investment = float(raw_input("Starting Investment: "))
#interest is the variable for interest rate. it is entered as a percentage so 5.5 would equate to 5.5%
interest = float(raw_input("Interest Rate as %, ex: 5.5 "))
#annual_fee is a variable that will hold the value for the annual fee.
annual_fee = float(raw_input("Annual Fee: "))
#years is a variable that we will use with a while loop, adding 1 to each year (but we wait until within the loop to do this)
years = 1
#we use a while loop as opposed to a for loop because we do not know how many times we will have to iterate through this loop to achieve a result. while true is always true, so this segment is going to run without conditions
while True:
#this is a variable that holds the value of our total money per year, this is equal to the initial investment + investment * interest percentage - our annual fee per year
#I actually had to try a few different things to get this to work, a regular expression may have been more suited to achieve an interest % that would be easier to work with. do some research on regular expressions in python as you will sooner or later need it.
total_per_year = investment + (years * (investment * (interest / 100))) - (annual_fee * years)
#now we start adding 1 to our years variable, since this is a while loop, this will recalculate the value of total_per_year variable
years += 1
#the conditional statement for when our total_per_year becomes equal to double our initial investment
if total_per_year >= 2 * investment:
#print years value (at time condition is met, so it will be 5 if it takes 5 years) and the string ' Years to Double Investment'
print years,' Years to Double Investment'
#prints 'You will have $' string and then the value our variable total_per_year
print 'You will have $', total_per_year
#this will break our while loop so that it does not run endlessly
break
#here is error handling for if the fee is larger than investment + interest
if (years * annual_fee) >= (years * (investment * (interest / 100))):
print('Annual Fee Exceeds Interest - Losing Money')
break
#initial call of our main function/begins loop
main()

Python and a "time value of money" problem

(I asked this question earlier today, but I did a poor job of explaining myself. Let me try again)
I have a client who is an industrial maintenance company. They sell service agreements that are prepaid 20 hour blocks of a technician's time. Some of their larger customers might burn through that agreement in two weeks while customers with fewer problems might go eight months on that same contract. I would like to use Python to help model projected sales revenue and determine how many billable hours per month that they'll be on the hook for.
If each customer only ever bought a single service contract (never renewed) it would be easy to figure sales as monthly_revenue = contract_value * qty_contracts_sold. Billable hours would also be easy: billable_hrs = hrs_per_contract * qty_contracts_sold. However, how do I account for renewals? Assuming that 90% (or some other arbitrary amount) of customers renew, then their monthly revenue ought to grow geometrically. Another important variable is how long the average customer burns through a contract. How do I determine what the revenue and billable hours will be 3, 6, or 12 months from now, based on various renewal and burn rates?
I assume that I'd use some type of recursive function but math was never one of my strong points. Any suggestions please?
Edit: I'm thinking that the best way to approach this is to think of it as a "time value of money" problem. I've retitled the question as such. The problem is probably a lot more common if you think of "monthly sales" as something similar to annuity payments.
If you want to consider the problem in terms of present value of future revenue (that's what "time value of money" implies to me), then you have the following parameters: discount rate D (on a monthly basis for convenience), time T a customer will take to exhaust their prepaid hours, likelihood L that they will renew when their prepaid hours are up, dollar amounts for first sale F and renewal R. This has several assumptions of course (maybe the customers who consume support faster are more likely to renew, for example -- this model doesn't account for that) but it may still be a useful first approximation.
So making a sale today is worth: F immediately for sure; plus, in T months, R more with probability L; plus, in 2T months, R more with probability LL; and so on. So the worth of that sale is F + RL / (DT) + RLL / (D2T) + ... = F + (R*L / DT ) * (1 + L/DT + L2/(DT)**2 + ...).
The series converges to 1 / (1 - L/(D**T)), so the overall formula in closed form (shifting to Python;-):
def salesworth(D, T, L, F, R):
return F + (R * L) / (D**T * (1 - L / (D**T)))
Expected billable hours can be had with the same formula, just using for F and R the number of hours in a first sale and renewal, and (if the discount rate concept does not apply to billable hours) a D of 1 (so T doesn't actually matter, as 1**T == 1 for any T;-).
Thanks for the assistance even though my requirements were a bit vague. After consulting someone who is extremely versed in financial mathematics, I determined that a simple formula was not an appropriate solution.
What I ended up doing is "exploding" the months into the component days using xrange() and iterating over each day. When evaluating each day, I determined whether a new contract was signed on that day, and if so, which dates in future the contract would need to be renewed. I pushed those renewal dates into a list and then summed the values.

Categories

Resources