Combine Multiple Functions for Maximal Efficiency

Functions should handle small, specific tasks. Do not write one large function that does an entirely specialized task that you will rarely need to perform. Remember, the goal of functions is to create shortcuts for us to instruct Python to perform a repetitive task, rather than re-writing those instructions each time we need a task to be performed.

You will find that one convenient use of functions is to combine them in a manner like what is shown below. We already have the better_wacc() function defined, which calculates a firm’s weighted average cost of capital. As alluded to above, a firm’s cost of equity is a function of its leverage ratio. So let’s create a function called cost_of_equity() that will determine a firm’s cost of equity capital. Recall that Modigliani and Miller proposition 2 states: $\( r_E = r_A + (r_A-r_D)*(1-t_C)*(D/E) \)\( where \)r_A$ is the unlevered cost of capital (equal to the cost of equity capital for a firm with no leverage).

Let us then define another function, firm_value() that calculates the value of a firm. Inside the firm_value() function, we will call both the better_wacc() function and the cost_of_equity() function.

def wacc(E, D, rE, rD, tC):
    if rE <= 0:
        raise Exception('rE is not positive')
    if rD <= 0:
        raise Exception('rD is not positive')
    if tC < 0:
        raise Exception('tC is negative')
    if rE <= rD:
        raise Exception('rE <= rD, M&M prop2 violated')
    if D > E:
        print('Warning, debt value exceeds equity value.  Did you accidentally flip these values?')
    V = E + D
    cost_of_capital = E / V * rE + D / V * rD * (1-tC)
    return cost_of_capital

def cost_of_equity(E, D, rA, rD, tC):
    return rA + (rA-rD)*(1-tC)*(D/E)

def firm_value(E, D, rA, rD, tC, FCF, g):
    rE = cost_of_equity(E=E, D=D, rA=rA, rD=rD, tC=tC)
    rW = wacc(E, D, rE, rD, tC)
    if rW < g:
        raise Exception('rW must be greater than g, but g=', g, 'and rW=', rW)
    return FCF / (rW - g)
firm_value(E=100, D=30, rA=.05, rD=.04, tC=.35, FCF=2, g=.01)

What happens if the firm had a different debt level?

firm_value(E=90, D=40, rA=.05, rD=.04, tC=.35, FCF=2, g=.01)

Debt is valuable because of the tax shield. You can see that this is the cause for the change in firm value by setting tC to zero and re-computing both values above.

print( firm_value(E=100, D=30, rA=.05, rD=.04, tC=0, FCF=2, g=.01) )
print( firm_value(E=90, D=40, rA=.05, rD=.04, tC=0, FCF=2, g=.01) )

Concept check: Estimate the cost of equity for a firm under two different scenarios.

  1. E=90, D=10, rA=.05, rD=.04, tC=.2

  2. E=10, D=90, rA=.05, rD=.04, tC=.2

print( cost_of_equity(E=90, D=10, rA=.05, rD=.04, tC=.2) )
print( cost_of_equity(E=10, D=90, rA=.05, rD=.04, tC=.2) )

The cost of equity for a firm with a lot of debt is much higher than the cost of equity for a firm with little debt.

Revisiting Tweets

Recall that earlier we made use of the .find() function for strings to check whether a tweet discussed a given company. We can turn this in to a function. Doing so will highlight a potentail efficiency gain of functions.

def scan_tweet(tweet, ticker):
    if tweet.find(ticker) > -1:
tic = 'AAPL'
t1 = 'AAPL announces plans to buy back stock.'
t2 = 'Earnings for AAPL beat analyst expectations.'
t3 = 'OMG look at this crazy kitten.'
scan_tweet(t1, tic)
scan_tweet(t2, tic)
scan_tweet(t3, tic)
AAPL announces plans to buy back stock.
Earnings for AAPL beat analyst expectations.