# Why is my put intrinsic value greater than my actual put value in BSM? Python code

I have been creating a class for determining put/call values based on the Black Scholes Merton model and have run into a weird problem. For some reason my put values end up being less than the intrinsic value of the option which simply doesn't make sense to me. I've scoured my code, rewritten it, and tried using someone else's code for determining the value of a put using BSM. Is there and error in my code, or am I missing some logic in BSM?

I'm using the most up to date version of python, NumPy, and scipy for this.

from numpy import exp, log, sqrt
from scipy.stats import norm


### basic inputs

K = 40
T = 0.5 # 1/2 year
r = 0.1
sigma = 0.2
o_t = 'p' # type of option
std_T = sqrt(T)
pv_factor = exp(-r * T)
start = 1
stop = 50


### sample data generation

st = np.linspace(start, stop, stop - start).astype(int) # potential prices at maturity
intrinsic = np.maximum(K - st, 0)

d1 = (log(st / K) + (r + 0.5 * sigma ** 2) * 0.5) / (sigma * sqrt(T))
d2 = d1 - sigma * sqrt(T)
nd1 = norm.cdf(-d1, 0.0, 1.0)
nd2 = norm.cdf(-d2, 0.0, 1.0)

puts = K * exp(-r * T) * nd2 - st * nd1


### simple plotting of intrinsic and extrinsic value

plt.figure(figsize=(10, 6))
plt.plot(st, intrinsic, 'b-.', lw=2.5, label='intrinsic value')


### plot inner value at maturity

plt.plot(st, puts, 'r', lw=2.5, label='present value')


### plot option present value

plt.grid(True)
plt.legend(loc=0)
plt.xlabel('index level $$S_0$$')
plt.ylabel('present value $$C(t=0)$$')


The answer to your question: A European put option can be priced below intrinsic value in a high interest rate environment (such as r=0.1) when stock price is low enough. That is due to time value of money. The american put would be immediately exercised, but the european one cannot and you just have to wait patiently until maturity to get your payoff. Until then the market value will be approximately $$e^{-r T} (K-S)$$ rather than $$K-S$$ where $$S \ll K$$.