You can do it quickly yourself if you have a little knowledge of computer programming. For example, Julia's charting capabilities are very good and you can quickly produce interactive figures. The below defines Black Scholes which is sufficient to match Bloomberg as shown here with Python and here with Julia. As long as you have Julia and the packages installed, you can simply copy paste the code to get this to work on your end.
using Plots, Distributions,DataFrames, PlotThemes
theme(:juno)
N(x) = cdf(Normal(0,1),x)
function BSM(S,K,t,rf,d,σ)
d1 = ( log(S/K) + (rf - d + 1/2*σ^2)*t ) / (σ*sqrt(t))
d2 = d1 - σ*sqrt(t)
c = exp(-d*t)S*N(d1) - exp(-rf*t)*K*N(d2)
return c
end
Adding a few lines computes the PnL (subtract initial cost), makes it dynamic (with slider for term and vol) and also allows you to play around with different notional values.
original_cost = BSM.(10,10,t,0.0,0.0,0.2)
function call(N, t_new, σ)
payoff_call = N.*(BSM.(S,10,t-t_new/365.0,0.0,0.0,σ) .- original_cost)
end
function start_val(N, σ)
payoff = N.*(BSM.(S,10,t,0.0,0.0,σ) .- original_cost)
end
S = 7:0.1:13
using Interact
call_gui = @manipulate for t_new = 1:1:364, σ = 0.01:0.01:0.41,
Notional = spinbox(label="Notional"; value=1);
plot(S,call(Notional, t_new, σ),
label = "Call Option PnL in $t_new days ($(t*365-t_new) days left to expiry)",
legendposition = :topleft,size = (800,500))
plot!(S, start_val(Notional, σ),
label = "Call Option Payoff Today with K = 10",
xlabel = "Spot",
ylabel = "Pnl",
size = (700,500),
title = "Option PnL for K = 10, t = 1 year, 0 divs and rates and 20% vol at initiation",
titlefontsize=10)
end
@layout! call_gui vbox(hbox(:t_new, :σ, :Notional),observe(_))
Now most equity markets are American, but in my example, the results would be identical for an American option anyways. In more general cases, you would need to implement this with a model that prices American options (PDE solver for example). In terms of looking at a chart, the differences will be so marginal that you can probably just stick with the European option pricing tool.
Theta (and all other Greeks) can be done in a similar way, as shown here. Examples below:
Or if you prefer 3D graphs, 18 lines of code define Black Scholes Merton including most relevant Greeks and chart all of them in one interactive chart:
function BSM(S,K,t,rf,d,σ)
d1 = ( log(S/K) + (rf - d + 1/2*σ^2)*t ) / (σ*sqrt(t))
d2 = d1 - σ*sqrt(t)
c = exp(-d*t)S*N(d1) - exp(-rf*t)*K*N(d2)
delta_c = exp(-d*t)*N(d1)
gamma_c = exp(-d*t)*n(d1) / (S*σ *sqrt(t))
theta_c =(-(S * exp(-d*t)*n(d1)* σ )/ (2 * sqrt(t)) - rf * K * exp(-rf*t) * N(d2) + d * S * exp(-d*t)*N(d1))/365
rho_c = ( K*t * exp(-d*t) * N(d2))*0.01
vega_c = S * exp(-d*t)*n(d1) * sqrt(t)*0.01
return c, vega_c, delta_c, gamma_c, theta_c, rho_c
end
spot,time, K_range, rf_range =7.0:0.5:18.0, range(0.0,stop=1.0,length=50), 5:0.5:20, 0.0:0.01:0.3
gui = @manipulate for K=K_range, rf=rf_range,d=d_range,σ = 0.01:0.1:1.11,α=0.1:0.1:1, side = 10:1:45,up = 20:2:52;
z = [Surface((spot,time)->BSM.(spot,K,time,rf,d,σ)[i], spot, time) for i in 1:1:6]
title = ["Call Value", "Vega","Delta","Gamma","Theta","Rho"]
p = [surface(spot,time,z[i], camera=(12,20),α=0.8 ,xlabel="Spot",ylabel="time",title=title[i],legend = :none) for i in 1:1:6]
plot(p[1],p[2],p[3],p[4],p[5],p[6],layout=(3,3), size =(1000,800))
end
@layout! gui vbox(vbox(hbox(K,rf,d,σ),hbox(α,side,up)), observe(_))
Another advantage with Julia is that it is super fast compared to other high level languages like Python. This is useful here because the short clip repriced ~50,000 options to get all 3D charts including adjustments. You can have a look at some basic explanations for the reason why Julia is so fast here. These are the results:
Last but not least, the WOLFRAM demonstrations project has a working app you can play around with that looks like this: