Usage¶
This page contains simple examples of pricing path-dependent options. For detailed documentation, refer to API References.
Get started¶
Import modules¶
In [1]: import qdpmc as qm
In [2]: import numpy as np
Set up parameters¶
Before pricing products, specify parameters of Monte Carlo simulation and market dynamics.
# Simulation parameters
In [3]: mc = qm.MonteCarlo(batch_size=125, num_iter=1000)
# Black-Scholes dynamics
In [4]: bs = qm.BlackScholes(r=0.03, q=0, v=0.25, day_counter=252)
Single-barrier options¶
This example in the index page demonstrates the
pricing of an up-and-out call option using qdpmc
.
To price an up-and-out put option, modify the associated codes:
# Specify an up-and-out call option
In [5]: up_out_call = qm.UpOut(
...: spot=100,
...: barrier=150,
...: rebate=0,
...: ob_days=np.linspace(1, 252, 252),
...: payoff=qm.Payoff(
...: qm.plain_vanilla,
...: strike=100,
...: option_type="call"
...: )
...: )
...:
# PV and Greek letters
In [6]: up_out_call.calc_value(mc, bs)
Out[6]: 6.435311521045284
Calculate Greeks¶
Request Greeks by specifying request_greeks
in calc_value
:
In [7]: up_out_call.calc_value(mc, bs, request_greeks=True)
Out[7]:
{'PV': 6.430979966605954,
'Delta': 0.1869394858552549,
'Gamma': -0.007855675540751743,
'Rho': 6.289757131357756,
'Vega': -20.446636793799605,
'Theta': 3.915152029320878e-05}
By default, the method uses central differences for Delta, Rho, and Vega. Change the steps and schemes by specifying the associated parameters.
In [8]: up_out_call.calc_value(mc, bs, request_greeks=True,
...: fd_steps={'ds':0.01, 'dr': 0.01, 'dv': 0.01},
...: fd_scheme={'ds': 'central', 'dr': 'forward',
...: 'dv': 'backward'})
...:
Out[8]:
{'PV': 6.402304146113466,
'Delta': 0.18180875644449906,
'Gamma': -0.025603082730435843,
'Rho': 15.781041288053938,
'Vega': -21.055319943466674,
'Theta': 3.073285944913474e-05}
Re-use random numbers¶
By default, each time calc_value
is run a different set of random
numbers is used (a different entropy is used to initialize
the random number generator.
Check out this page
for details about NumPy
random number generator).
To reuse the same set of random numbers, run the following codes:
In [9]: e = mc.most_recent_entropy
In [10]: up_out_call.calc_value(mc, bs, entropy=e)
Out[10]: 6.402304146113474
Time-varying barrier level¶
If a scalar is passed to barrier
, the barrier is then assumed to
be time-invariant. Pass an array to barrier
to specify a time-varying
barrier level. However, note that this array should match the length of
ob_days
.
In [11]: time_varying_barrier = np.linspace(120, 130, 252)
In [12]: time_varying_barrier_option = qm.UpOut(
....: spot=100,
....: barrier=time_varying_barrier,
....: rebate=0,
....: ob_days=np.linspace(1, 252, 252),
....: payoff=qm.Payoff(
....: qm.plain_vanilla,
....: strike=100,
....: option_type="call"
....: )
....: )
....:
In [13]: time_varying_barrier_option.calc_value(mc, bs)
Out[13]: 1.9411275446277678
Define payoff function¶
To customize a payoff function, define a Payoff:
In [14]: def dsf_payoff(s, k1, k2):
....: call = qm.plain_vanilla(s, k1, 'call')
....: put = qm.plain_vanilla(s, k2, 'put')
....: return call + put
....:
In [15]: dsf = qm.DoubleOut(
....: spot=100,
....: barrier_up=120,
....: barrier_down=90,
....: ob_days_up=np.linspace(1, 252, 252),
....: ob_days_down=np.linspace(21, 252, 12),
....: payoff=qm.Payoff(
....: func=dsf_payoff,
....: k1=100, k2=110
....: ),
....: rebate_up=3,
....: rebate_down=2
....: )
....:
In [16]: dsf.calc_value(mc, bs)
Out[16]: 3.2037753324400757