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)$')