Derivatives Portfolio Risk Statistics ===================================== From a risk management perspective it is important to know **how sensitive derivatives portfolios are** with regard to certain parameter values (market quotes, model assumptions, etc.). This part illustrates how to generate certain **risk reports** for ``derivatives_portfolio`` objects. .. code:: python import dx import datetime as dt import time import numpy as np Risk Factors ------------ The example is based on **two risk factors**, both modeled as geometric Brownian motions. .. code:: python # constant short rate r = dx.constant_short_rate('r', 0.01) .. code:: python # market environment me_gbm_1 = dx.market_environment('gbm_1', dt.datetime(2015, 1, 1)) .. code:: python # geometric Brownian motion me_gbm_1.add_constant('initial_value', 40.) me_gbm_1.add_constant('volatility', 0.2) me_gbm_1.add_constant('currency', 'EUR') me_gbm_1.add_constant('model', 'gbm') .. code:: python me_gbm_2 = dx.market_environment('gbm_2', me_gbm_1.pricing_date) .. code:: python # valuation environment val_env = dx.market_environment('val_env', dt.datetime(2015, 1, 1)) val_env.add_constant('paths', 25000) # 25,000 paths val_env.add_constant('frequency', 'W') # weekly frequency 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)) .. code:: python # add valuation environment to market environments me_gbm_1.add_environment(val_env) me_gbm_2.add_environment(me_gbm_1) me_gbm_2.add_constant('initial_value', 40.) me_gbm_2.add_constant('volatility', 0.5) # higher volatility .. code:: python risk_factors = {'gbm_1' : me_gbm_1, 'gbm_2' : me_gbm_2} # market with two risk factors Derivatives Positions --------------------- We are going to model **total of 6 derivatives positions**. Market Environment ~~~~~~~~~~~~~~~~~~ All derivatives instruments (positions) share the same ``market_environment`` object. .. code:: python # market environment for the options me_option = dx.market_environment('put', dt.datetime(2015, 1, 1)) me_option.add_constant('maturity', dt.datetime(2015, 12, 31)) me_option.add_constant('currency', 'EUR') me_option.add_environment(val_env) Derivatives Positions ~~~~~~~~~~~~~~~~~~~~~ Two different kinds of derivatives make up the portfolio---an **American put option** and a **European maximum call option**. Both types of derivatives populate three positions, respectively. .. code:: python positions = {} half = 3 # 2 times that many options for i in range(half): name = 'am_put_pos_%s' %i # same name for position key and name positions[name] = dx.derivatives_position( name=name, quantity=1, underlyings=['gbm_1'], mar_env=me_option, otype='American single', payoff_func='np.maximum(instrument_values - 40., 0)') multi_payoff = "np.maximum(np.maximum(maturity_value['gbm_1'], maturity_value['gbm_2']) - 40., 0)" for i in range(half, 2 * half): name = 'multi_pos_%s' %i # same name for position key and name positions[name] = dx.derivatives_position( name=name, quantity=1, underlyings=['gbm_1', 'gbm_2'], mar_env=me_option, otype='European multi', payoff_func=multi_payoff) Portfolio Modeling and Valuation -------------------------------- The instantiation of the ``derivatives_portfolio`` object is as usual. .. code:: python portfolio = dx.derivatives_portfolio( name='portfolio', positions=positions, val_env=val_env, risk_factors=risk_factors, correlations=None, parallel=False) .. code:: python %time res = portfolio.get_values(fixed_seed=True) .. parsed-literal:: Total pos_value 40.971 dtype: float64 CPU times: user 724 ms, sys: 4 ms, total: 728 ms Wall time: 728 ms Here, the **value estimates** from the Monte Carlo simulation and valuation. .. code:: python res .. raw:: html
position name quantity otype risk_facts value currency pos_value
0 am_put_pos_2 am_put_pos_2 1 American single [gbm_1] 3.317 EUR 3.317
1 am_put_pos_0 am_put_pos_0 1 American single [gbm_1] 3.341 EUR 3.341
2 am_put_pos_1 am_put_pos_1 1 American single [gbm_1] 3.323 EUR 3.323
3 multi_pos_3 multi_pos_3 1 European multi [gbm_1, gbm_2] 10.330 EUR 10.330
4 multi_pos_4 multi_pos_4 1 European multi [gbm_1, gbm_2] 10.330 EUR 10.330
5 multi_pos_5 multi_pos_5 1 European multi [gbm_1, gbm_2] 10.330 EUR 10.330
Portfolio Risk Reports ---------------------- Portfolio risk reports are meant to provide a broad overview of how sensitive the value of a portfolio is with regard to the value of certain input parameters (market data, model parameters). While **Greeks** provide the same information with regard to marginal changes in the input paramters, risk reports provide a **wider range input-output (parameter-portfolio value) combinations**. No Correlation ~~~~~~~~~~~~~~ First, consider the portfolio from before, i.e. **without correlation**. .. code:: python portfolio.val_env.get_list('cholesky_matrix') .. parsed-literal:: array([[ 1., 0.], [ 0., 1.]]) Calling the method ``get_port_risk`` and providing a key for the respetive Greek yields sensitivities with regard to all risk factors (here: ``gbm_1`` and ``gbm_2``). portfolio.valuation_objects[3].underlying_objects['gbm_1'].update(initial_value=15) .. code:: python %%time vegas, benchvalue = portfolio.get_port_risk(Greek='Vega', fixed_seed=True) .. parsed-literal:: gbm_1 0.8 0.9 1.0 1.1 1.2 gbm_2 0.8 0.9 1.0 1.1 1.2 CPU times: user 5.04 s, sys: 0 ns, total: 5.04 s Wall time: 5.04 s The return object is a pandas ``Panel`` object. .. code:: python vegas .. parsed-literal:: Dimensions: 2 (items) x 5 (major_axis) x 2 (minor_axis) Items axis: gbm_1_Vega to gbm_2_Vega Major_axis axis: 0.8 to 1.2 Minor_axis axis: factor to value Using the helper funtion ``risk_report`` allows the easy, readable printout of the results, i.e. the **portfolio volatility sensitivities**. In this case you can see that, for example, the increase in the first risk fator's (``gbm_1``) volatility by 10% leads to a portfolio value increase bya bit less than 1 currency unit. Decreasing the same input parameter by 10% reduces the portfolio value by a bit less than 1 currency unit. .. code:: python dx.risk_report(vegas) .. parsed-literal:: gbm_1_Vega 0.8 0.9 1.0 1.1 1.2 factor 0.16 0.18 0.20 0.22 0.24 value 32.31 33.25 40.96 35.11 35.99 gbm_2_Vega 0.8 0.9 1.0 1.1 1.2 factor 0.40 0.45 0.50 0.55 0.60 value 29.45 31.82 40.96 36.52 38.86 Of course, you can generate the same risk report for the **portfolio initial value sensitivities**. .. code:: python %time deltas, benchvalue = portfolio.get_port_risk(Greek='Delta', fixed_seed=True) .. parsed-literal:: gbm_1 0.8 0.9 1.0 1.1 1.2 gbm_2 0.8 0.9 1.0 1.1 1.2 CPU times: user 5.38 s, sys: 3 ms, total: 5.38 s Wall time: 5.38 s For example, increasing the initial value of the first risk factor (``gbm_1``) by 10% increases the portfolio value by about 11 currency units. .. code:: python dx.risk_report(deltas) .. parsed-literal:: gbm_1_Delta 0.8 0.9 1.0 1.1 1.2 factor 32.00 36.00 40.00 44.00 48.00 value 25.48 28.44 40.96 45.31 61.36 gbm_2_Delta 0.8 0.9 1.0 1.1 1.2 factor 32.00 36.00 40.00 44.0 48.00 value 24.14 28.31 40.96 41.6 50.09 .. code:: python dx.risk_report(deltas.ix[:, :, 'value'] - benchvalue) .. parsed-literal:: gbm_1_Delta 0.8 -15.49 0.9 -12.53 1.0 0.00 1.1 4.34 1.2 20.39 Name: gbm_1_Delta, dtype: float64 gbm_2_Delta 0.8 -16.83 0.9 -12.65 1.0 0.00 1.1 0.64 1.2 9.13 Name: gbm_2_Delta, dtype: float64 With Correlation ~~~~~~~~~~~~~~~~ Consider now a **highly negative correlation** case. .. code:: python correlations = [['gbm_1', 'gbm_2', -0.9]] .. code:: python portfolio = dx.derivatives_portfolio( 'portfolio', positions, val_env, risk_factors, correlations, parallel=False) .. code:: python portfolio.val_env.get_list('cholesky_matrix') .. parsed-literal:: array([[ 1. , 0. ], [-0.9 , 0.43588989]]) Since the value of the European maximum call option is dependent on the risk factor correlation you see a **significant change in this derivative's value estimate**. .. code:: python %time portfolio.get_values(fixed_seed=True) .. parsed-literal:: Total pos_value 44.112 dtype: float64 CPU times: user 658 ms, sys: 0 ns, total: 658 ms Wall time: 658 ms .. raw:: html
position name quantity otype risk_facts value currency pos_value
0 am_put_pos_2 am_put_pos_2 1 American single [gbm_1] 3.293 EUR 3.293
1 am_put_pos_0 am_put_pos_0 1 American single [gbm_1] 3.293 EUR 3.293
2 am_put_pos_1 am_put_pos_1 1 American single [gbm_1] 3.293 EUR 3.293
3 multi_pos_3 multi_pos_3 1 European multi [gbm_1, gbm_2] 11.411 EUR 11.411
4 multi_pos_4 multi_pos_4 1 European multi [gbm_1, gbm_2] 11.411 EUR 11.411
5 multi_pos_5 multi_pos_5 1 European multi [gbm_1, gbm_2] 11.411 EUR 11.411
Via the ``step`` parameter, you can influence the **granularity of the risk report**. .. code:: python %%time deltas, benchvalue = portfolio.get_port_risk(Greek='Delta', fixed_seed=True, step=0.05) .. parsed-literal:: gbm_1 0.8 0.85 0.9 0.95 1.0 1.05 1.1 1.15 1.2 gbm_2 0.8 0.85 0.9 0.95 1.0 1.05 1.1 1.15 1.2 CPU times: user 7.82 s, sys: 3 ms, total: 7.83 s Wall time: 7.83 s In this case, an increase in the intial value of the first risk factor (``gbm_1``) by 10% leads to a **much higher increase** in the portfolio value of about 15 currency units. .. code:: python dx.risk_report(deltas) .. parsed-literal:: gbm_1_Delta 0.80 0.85 0.90 0.95 1.00 1.05 1.10 1.15 1.20 factor 32.0 34.00 36.00 38.00 40.00 42.00 44.00 46.00 48.00 value 27.2 29.65 33.23 38.12 44.11 51.06 58.96 67.64 76.98 gbm_2_Delta 0.80 0.85 0.90 0.95 1.00 1.05 1.10 1.15 1.20 factor 32.00 34.00 36.00 38.00 40.00 42.00 44.00 46.0 48.00 value 31.67 34.38 37.36 40.62 44.11 47.82 51.73 55.8 60.02 .. code:: python dx.risk_report(deltas.ix[:, :, 'value'] - benchvalue) .. parsed-literal:: gbm_1_Delta 0.80 -16.92 0.85 -14.46 0.90 -10.88 0.95 -5.99 1.00 0.00 1.05 6.94 1.10 14.85 1.15 23.53 1.20 32.86 Name: gbm_1_Delta, dtype: float64 gbm_2_Delta 0.80 -12.45 0.85 -9.74 0.90 -6.75 0.95 -3.49 1.00 0.00 1.05 3.71 1.10 7.62 1.15 11.69 1.20 15.91 Name: gbm_2_Delta, dtype: float64 **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