Multi-Risk Derivatives Portfolios ================================= The step from multi-risk derivatives instruments to multi-risk derivatives instrument portfolios is not a too large one. This part of the tutorial shows how to model an economy with three risk factors .. code:: python from dx import * import seaborn as sns; sns.set() Risk Factors ------------ This sub-section models the single risk factors. We start with definition of the risk-neutral discounting object. .. code:: python # constant short rate r = constant_short_rate('r', 0.02) **Three risk factors** ares modeled: - geometric Brownian motion - jump diffusion - stochastic volatility process .. code:: python # 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)) Assumptions for the ``geometric_brownian_motion`` object. .. code:: python # 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') Assumptions for the ``jump_diffusion`` object. .. code:: python # 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') Assumptions for the ``stochastic_volatility`` object. .. code:: python # 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('currency', 'EUR') me_sv.add_constant('model', 'sv') Finally, the unifying valuation assumption for the **valuation environment**. .. code:: python # valuation environment val_env = market_environment('val_env', dt.datetime(2015, 1, 1)) val_env.add_constant('paths', 10000) val_env.add_constant('frequency', 'W') 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)) These are added to the single ``market_environment`` objects of the risk factors. .. code:: python # add valuation environment to market environments me_gbm.add_environment(val_env) me_jd.add_environment(val_env) me_sv.add_environment(val_env) Finally, the **market model** with the risk factors and the correlations between them. .. code:: python risk_factors = {'gbm' : me_gbm, 'jd' : me_jd, 'sv' : me_sv} correlations = [['gbm', 'jd', 0.66], ['jd', 'sv', -0.75]] Derivatives ----------- In this sub-section, we model the single derivatives instruments. American Put Option ~~~~~~~~~~~~~~~~~~~ The first derivative instrument is an **American put option**. .. code:: python gbm = geometric_brownian_motion('gbm_obj', me_gbm) .. code:: python 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) .. code:: python am_put = valuation_mcs_american_single('am_put', mar_env=me_put, underlying=gbm, payoff_func='np.maximum(strike - instrument_values, 0)') .. code:: python am_put.present_value(fixed_seed=True, bf=5) .. parsed-literal:: 5.012 European Maximum Call on 2 Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The second derivative instrument is a **European maximum call option on two risk factors**. .. code:: python jd = jump_diffusion('jd_obj', me_jd) .. code:: python 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) .. code:: python payoff_call = "np.maximum(np.maximum(maturity_value['gbm'], maturity_value['jd']) - 34., 0)" .. code:: python assets = {'gbm' : me_gbm, 'jd' : me_jd} asset_corr = [correlations[0]] .. code:: python asset_corr .. parsed-literal:: [['gbm', 'jd', 0.66]] .. code:: python max_call = valuation_mcs_european_multi('max_call', me_max_call, assets, asset_corr, payoff_func=payoff_call) .. code:: python max_call.present_value(fixed_seed=False) .. parsed-literal:: 8.334 .. code:: python max_call.delta('jd') .. parsed-literal:: 0.7597222222222231 .. code:: python max_call.delta('gbm') .. parsed-literal:: 0.2819444444444461 American Minimum Put on 2 Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The third derivative instrument is an **American minimum put on two risk factors**. .. code:: python sv = stochastic_volatility('sv_obj', me_sv) .. code:: python 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) .. code:: python payoff_put = "np.maximum(32. - np.minimum(instrument_values['jd'], instrument_values['sv']), 0)" .. code:: python assets = {'jd' : me_jd, 'sv' : me_sv} asset_corr = [correlations[1]] asset_corr .. parsed-literal:: [['jd', 'sv', -0.75]] .. code:: python min_put = valuation_mcs_american_multi( 'min_put', val_env=me_min_put, risk_factors=assets, correlations=asset_corr, payoff_func=payoff_put) .. code:: python min_put.present_value(fixed_seed=True) .. parsed-literal:: 4.302 .. code:: python min_put.delta('jd') .. parsed-literal:: -0.1083333333333325 .. code:: python min_put.delta('sv') .. parsed-literal:: -0.21944444444444372 Portfolio --------- To compose a derivatives portfolio, ``derivatives_position`` objects are needed. .. code:: python am_put_pos = derivatives_position( name='am_put_pos', quantity=2, underlyings=['gbm'], mar_env=me_put, otype='American single', payoff_func='np.maximum(instrument_values - 36., 0)') .. code:: python max_call_pos = derivatives_position( 'max_call_pos', 3, ['gbm', 'jd'], me_max_call, 'European multi', payoff_call) .. code:: python min_put_pos = derivatives_position( 'min_put_pos', 5, ['sv', 'jd'], me_min_put, 'American multi', payoff_put) These objects are to be collected in ``dictionary`` objects. .. code:: python positions = {'am_put_pos' : am_put_pos, 'max_call_pos' : max_call_pos, 'min_put_pos' : min_put_pos} All is together to instantiate the ``derivatives_portfolio`` class. .. code:: python port = derivatives_portfolio(name='portfolio', positions=positions, val_env=val_env, risk_factors=risk_factors, correlations=correlations) Let us have a look at the major **portfolio statistics**. .. code:: python %time stats = port.get_statistics() stats .. parsed-literal:: Totals pos_value 51.764 dtype: float64 CPU times: user 1.72 s, sys: 3 ms, total: 1.72 s Wall time: 1.72 s .. raw:: html
position name quantity otype risk_facts value currency pos_value pos_delta pos_vega
0 max_call_pos max_call_pos 3 European multi [gbm, jd] 8.165 EUR 24.495 {'jd': 2.266667, 'gbm': 0.866667} {'jd': 10.5, 'gbm': 15.0}
1 am_put_pos am_put_pos 2 American single [gbm] 3.182 EUR 6.364 1.2166 30.4
2 min_put_pos min_put_pos 5 American multi [sv, jd] 4.181 EUR 20.905 {'jd': -0.618056, 'sv': -1.180556} {'jd': 10.0, 'sv': 10.0}
.. code:: python stats['pos_value'].sum() .. parsed-literal:: 51.763999999999996 Finally, a graphical look at **two selected, simulated paths** of the stochastic volatility risk factor and the jump diffusion risk factor, respectively. .. code:: python path_no = 1 paths1 = port.underlying_objects['sv'].get_instrument_values()[:, path_no] paths2 = port.underlying_objects['jd'].get_instrument_values()[:, path_no] .. code:: python paths1 .. parsed-literal:: array([ 36. , 36.34884124, 34.9130166 , 36.31001777, 34.85894675, 35.63213975, 39.0707393 , 44.35899961, 44.47413556, 43.13168786, 47.48647475, 46.27393881, 43.49655379, 47.23009583, 49.53908109, 43.71731937, 51.76008829, 52.58524036, 54.2573447 , 51.6460015 , 44.28088435, 39.01540236, 32.91109921, 30.24790867, 29.61667412, 31.76473582, 27.30258542, 28.39127869, 28.23333544, 27.08972766, 27.32993764, 28.65926992, 26.9785575 , 31.8938528 , 34.58971037, 32.7699367 , 29.35365969, 28.66856698, 31.14196767, 31.37051847, 30.10832392, 33.11928276, 34.48108709, 32.97416103, 28.08648082, 26.52705819, 21.57771857, 20.42912064, 20.99231801, 19.23163105, 21.37234395, 20.80944619, 20.73301676, 20.79953889, 20.34822548, 18.69820953]) .. code:: python paths2 .. parsed-literal:: array([ 36. , 36.09036184, 37.30618631, 36.53472814, 36.79572901, 36.66944957, 35.56227649, 33.3644349 , 33.42674479, 34.22659123, 32.22562864, 33.05209641, 33.82798732, 33.20431052, 33.78753542, 36.17164509, 33.76072474, 33.00278459, 32.79744011, 33.50195594, 34.40874205, 34.57037634, 37.00098086, 37.7309694 , 38.32223737, 38.2477447 , 39.92233666, 39.6591103 , 39.43998269, 39.88306801, 40.35338195, 40.23418088, 41.48106905, 39.66194269, 39.32622142, 39.48978055, 40.67396363, 40.76122376, 40.00499204, 39.725126 , 40.05448393, 39.06546207, 37.674332 , 38.48264394, 40.86222422, 41.3749628 , 44.02458974, 45.32751049, 44.704871 , 45.06224883, 43.38741804, 43.68855748, 44.75023229, 45.4285521 , 45.27511078, 45.68070094]) The resulting plot illustrates the strong **negative correlation**. .. code:: python import matplotlib.pyplot as plt %matplotlib inline plt.figure(figsize=(10, 6)) 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 .. image:: 05_dx_portfolio_multi_risk_files/05_dx_portfolio_multi_risk_67_0.png **Copyright, License & Disclaimer** © Dr. Yves J. Hilpisch \| The Python Quants GmbH DX Analytics (the "dx library") is licensed under the GNU Affero General Public License version 3 or later (see http://www.gnu.org/licenses/). DX Analytics comes with no representations or warranties, to the extent permitted by applicable law. http://tpq.io \| team@tpq.io \| http://twitter.com/dyjh **Quant Platform** \| http://quant-platform.com **Derivatives Analytics with Python (Wiley Finance)** \| http://derivatives-analytics-with-python.com **Python for Finance (O'Reilly)** \| http://python-for-finance.com