The Python Quants

DX Analytics Library

Portfolio with Multi-Risk Derivatives

In [1]:
from dx import *

Assets

In [2]:
# constant short rate
r = constant_short_rate('r', 0.02)
In [3]:
# market environments
me_gbm = market_environment('gbm', dt.datetime(2015, 1, 1))
me_jd = market_environment('jd', dt.datetime(2015, 1, 1))
me_sv = market_environment('sv', dt.datetime(2015, 1, 1))
In [4]:
# geometric Brownian motion
me_gbm.add_constant('initial_value', 36.)
me_gbm.add_constant('volatility', 0.2) 
me_gbm.add_constant('currency', 'EUR')
me_gbm.add_constant('model', 'gbm')
In [5]:
# jump diffusion
me_jd.add_constant('initial_value', 36.)
me_jd.add_constant('volatility', 0.2)
me_jd.add_constant('lambda', 0.5)
    # probability for jump p.a.
me_jd.add_constant('mu', -0.75)
    # expected jump size [%]
me_jd.add_constant('delta', 0.1)
    # volatility of jump
me_jd.add_constant('currency', 'EUR')
me_jd.add_constant('model', 'jd')
In [6]:
# stochastic volatility model
me_sv.add_constant('initial_value', 36.)
me_sv.add_constant('volatility', 0.2)
me_sv.add_constant('vol_vol', 0.1)
me_sv.add_constant('kappa', 2.5)
me_sv.add_constant('theta', 0.4)
me_sv.add_constant('rho', -0.5)
me_sv.add_constant('lambda', 0.0)
    # probability for jump p.a.
me_sv.add_constant('mu', 0.0)
    # expected jump size [%]
me_sv.add_constant('delta', 0.0)
    # volatility of jump
me_sv.add_constant('currency', 'EUR')
me_sv.add_constant('model', 'svjd')
In [7]:
# valuation environment
val_env = market_environment('val_env', dt.datetime(2015, 1, 1))
val_env.add_constant('paths', 10000)
val_env.add_constant('frequency', 'M')
val_env.add_curve('discount_curve', r)
val_env.add_constant('starting_date', dt.datetime(2015, 1, 1))
val_env.add_constant('final_date', dt.datetime(2015, 12, 31))
In [8]:
# add valuation environment to market environments
me_gbm.add_environment(val_env)
me_jd.add_environment(val_env)
me_sv.add_environment(val_env)
In [9]:
underlyings = {'gbm' : me_gbm, 'jd' : me_jd, 'sv' : me_sv}
correlations = [['gbm', 'jd', 0.66], ['jd', 'sv', -0.75]]

Derivatives

American Put Option

In [10]:
gbm = geometric_brownian_motion('gbm_obj', me_gbm)
In [11]:
me_put = market_environment('put', dt.datetime(2015, 1, 1))
me_put.add_constant('maturity', dt.datetime(2015, 12, 31))
me_put.add_constant('strike', 40.)
me_put.add_constant('currency', 'EUR')
me_put.add_environment(val_env)
In [12]:
am_put = valuation_mcs_american_single('am_put', mar_env=me_put, underlying=gbm,
                       payoff_func='np.maximum(strike - instrument_values, 0)')
In [13]:
am_put.present_value(fixed_seed=True, bf=3)
Out[13]:
5.00565

European Maximum Call on 2 Assets

In [14]:
jd = jump_diffusion('jd_obj', me_jd)
In [15]:
me_max_call = market_environment('put', dt.datetime(2015, 1, 1))
me_max_call.add_constant('maturity', dt.datetime(2015, 9, 15))
me_max_call.add_constant('currency', 'EUR')
me_max_call.add_environment(val_env)
In [16]:
payoff_call = "np.maximum(np.maximum(maturity_value['gbm'], maturity_value['jd']) - 34., 0)"
In [17]:
assets = {'gbm' : me_gbm, 'jd' : me_jd}
asset_corr = [correlations[0]]
In [18]:
asset_corr
Out[18]:
[['gbm', 'jd', 0.66]]
In [19]:
max_call = valuation_mcs_european_multi('max_call', me_max_call, assets, asset_corr,
        payoff_func=payoff_call)
In [20]:
max_call.present_value(fixed_seed=False)
Out[20]:
4.936961
In [21]:
max_call.delta('jd')
Out[21]:
0.31050138888888906
In [22]:
max_call.delta('gbm')
Out[22]:
0.5396388888888888

American Minimum Put on 2 Assets

In [23]:
sv = jump_diffusion('sv_obj', me_sv)
In [24]:
me_min_put = market_environment('min_put', dt.datetime(2015, 1, 1))
me_min_put.add_constant('maturity', dt.datetime(2015, 6, 17))
me_min_put.add_constant('currency', 'EUR')
me_min_put.add_environment(val_env)
In [25]:
payoff_put = "np.maximum(32. - np.minimum(instrument_values['jd'], instrument_values['sv']), 0)"
In [26]:
assets = {'jd' : me_jd, 'sv' : me_sv}
asset_corr = [correlations[1]]
asset_corr
Out[26]:
[['jd', 'sv', -0.75]]
In [27]:
min_put = valuation_mcs_american_multi('min_put', val_env=me_min_put, assets=assets,
                       correlations=asset_corr, payoff_func=payoff_put)
In [28]:
min_put.present_value(fixed_seed=True)
Out[28]:
5.627675
In [29]:
min_put.delta('jd')
Out[29]:
-0.1933402777777772
In [30]:
min_put.delta('sv')
Out[30]:
-0.2347958333333332

Portfolio

In [31]:
am_put_pos = derivatives_position('am_put_pos', 2, ['gbm'], me_put, 'American single',
                      'np.maximum(instrument_values - 36., 0)')
In [32]:
max_call_pos = derivatives_position('max_call_pos', 3, ['gbm', 'jd'], me_max_call, 'European multi',
                      payoff_call)
In [33]:
min_put_pos = derivatives_position('min_put_pos', 5, ['sv', 'jd'], me_min_put, 'American multi',
                      payoff_put)
In [34]:
positions = {'am_put_pos' : am_put_pos, 'max_call_pos' : max_call_pos,
             'min_put_pos' : min_put_pos}
In [35]:
port = derivatives_portfolio('portfolio', positions, val_env, underlyings, correlations)
In [36]:
port.time_grid
Out[36]:
array([datetime.datetime(2015, 1, 1, 0, 0),
       datetime.datetime(2015, 1, 31, 0, 0),
       datetime.datetime(2015, 2, 28, 0, 0),
       datetime.datetime(2015, 3, 31, 0, 0),
       datetime.datetime(2015, 4, 30, 0, 0),
       datetime.datetime(2015, 5, 31, 0, 0),
       datetime.datetime(2015, 6, 17, 0, 0),
       datetime.datetime(2015, 6, 30, 0, 0),
       datetime.datetime(2015, 7, 31, 0, 0),
       datetime.datetime(2015, 8, 31, 0, 0),
       datetime.datetime(2015, 9, 15, 0, 0),
       datetime.datetime(2015, 9, 30, 0, 0),
       datetime.datetime(2015, 10, 31, 0, 0),
       datetime.datetime(2015, 11, 30, 0, 0),
       datetime.datetime(2015, 12, 31, 0, 0)], dtype=object)
In [37]:
port.get_statistics()
Out[37]:
position name quantity value currency pos_value pos_delta pos_vega
0 max_call_pos max_call_pos 3 4.717473 EUR 14.152419 {'jd': 0.9635, 'gbm': 1.597504} {'jd': 17.4321, 'gbm': 27.6066}
1 am_put_pos am_put_pos 2 3.253842 EUR 6.507684 1.1682 29.2524
2 min_put_pos min_put_pos 5 5.193298 EUR 25.966490 {'jd': -0.873333, 'sv': -1.092486} {'jd': 29.61, 'sv': 10.297}

3 rows × 8 columns

In [38]:
path_no = 1
paths1 = port.underlying_objects['sv'].get_instrument_values()[:, path_no]
paths2 = port.underlying_objects['jd'].get_instrument_values()[:, path_no]
In [39]:
paths1
Out[39]:
array([ 36.        ,  31.68594897,  33.17014295,  28.85478614,
        25.23873562,  25.48025923,  23.52184359,  18.19276475,
        16.96665329,  19.94559018,  21.04948442,  23.24390163,
        29.36386086,  27.18016546,  29.21790093])
In [40]:
paths2
Out[40]:
array([ 36.        ,  36.55096144,  37.03896276,  38.71767428,
        41.88393042,  37.10340111,  38.00142478,  41.48705434,
        45.340064  ,  44.5607981 ,  45.13594141,  44.93476892,
        45.01938026,  45.25732557,  43.41010751])
In [41]:
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(port.time_grid, paths1, 'r', label='sv')
plt.plot(port.time_grid, paths2, 'b', label='jd')
plt.gcf().autofmt_xdate()
plt.legend(loc=0); plt.grid(True)
# negatively correlated underlyings