Quite Complex Portfolios ======================== This part illustrates that you can **model, value and risk manage quite complex derivatives portfolios** with DX Analytics. .. code:: python from dx import * import time import matplotlib.pyplot as plt import seaborn as sns; sns.set() %matplotlib inline np.random.seed(10000) Multiple Risk Factors --------------------- The example is based on a **multiple, correlated risk factors**, all (for the ease of exposition) ``geometric_brownian_motion`` objects. .. code:: python mer = market_environment(name='me', pricing_date=dt.datetime(2015, 1, 1)) mer.add_constant('initial_value', 0.01) mer.add_constant('volatility', 0.1) mer.add_constant('kappa', 2.0) mer.add_constant('theta', 0.05) mer.add_constant('paths', 100) # dummy mer.add_constant('frequency', 'M') # dummy mer.add_constant('starting_date', mer.pricing_date) mer.add_constant('final_date', dt.datetime(2015, 12, 31)) # dummy ssr = stochastic_short_rate('ssr', mer) .. code:: python plt.figure(figsize=(10, 6)) plt.plot(ssr.process.time_grid, ssr.process.get_instrument_values()[:, :10]); plt.gcf().autofmt_xdate() .. image:: 13_dx_quite_complex_portfolios_files/13_dx_quite_complex_portfolios_7_0.png .. code:: python # market environments me = market_environment('gbm', dt.datetime(2015, 1, 1)) .. code:: python # geometric Brownian motion me.add_constant('initial_value', 36.) me.add_constant('volatility', 0.2) me.add_constant('currency', 'EUR') .. code:: python # jump diffusion me.add_constant('lambda', 0.4) me.add_constant('mu', -0.4) me.add_constant('delta', 0.2) .. code:: python # stochastic volatility me.add_constant('kappa', 2.0) me.add_constant('theta', 0.3) me.add_constant('vol_vol', 0.5) me.add_constant('rho', -0.5) Using 2,500 paths and monthly discretization for the example. .. code:: python # valuation environment val_env = market_environment('val_env', dt.datetime(2015, 1, 1)) val_env.add_constant('paths', 2500) val_env.add_constant('frequency', 'M') val_env.add_curve('discount_curve', ssr) val_env.add_constant('starting_date', dt.datetime(2015, 1, 1)) val_env.add_constant('final_date', dt.datetime(2016, 12, 31)) .. code:: python # add valuation environment to market environments me.add_environment(val_env) .. code:: python no = 50 # 50 different risk factors in total .. code:: python risk_factors = {} for rf in range(no): # random model choice sm = np.random.choice(['gbm', 'jd', 'sv']) key = '%3d_%s' % (rf + 1, sm) risk_factors[key] = market_environment(key, me.pricing_date) risk_factors[key].add_environment(me) # random initial_value risk_factors[key].add_constant('initial_value', np.random.random() * 40. + 20.) # radnom volatility risk_factors[key].add_constant('volatility', np.random.random() * 0.6 + 0.05) # the simulation model to choose risk_factors[key].add_constant('model', sm) .. code:: python correlations = [] keys = sorted(risk_factors.keys()) for key in keys[1:]: correlations.append([keys[0], key, np.random.choice([-0.1, 0.0, 0.1])]) correlations[:3] .. parsed-literal:: [[' 1_sv', ' 2_gbm', 0.10000000000000001], [' 1_sv', ' 3_gbm', -0.10000000000000001], [' 1_sv', ' 4_gbm', -0.10000000000000001]] Options Modeling ---------------- We model a certain number of **derivative instruments** with the following major assumptions. .. code:: python me_option = market_environment('option', me.pricing_date) # choose from a set of maturity dates (month ends) maturities = pd.date_range(start=me.pricing_date, end=val_env.get_constant('final_date'), freq='M').to_pydatetime() me_option.add_constant('maturity', np.random.choice(maturities)) me_option.add_constant('currency', 'EUR') me_option.add_environment(val_env) Portfolio Modeling ------------------ The ``derivatives_portfolio`` object we compose consists of **multiple derivatives positions**. Each option differs with respect to the strike and the risk factor it is dependent on. .. code:: python # 5 times the number of risk factors # as portfolio positions/instruments pos = 5 * no .. code:: python positions = {} for i in range(pos): ot = np.random.choice(['am_put', 'eur_call']) if ot == 'am_put': otype = 'American single' payoff_func = 'np.maximum(%5.3f - instrument_values, 0)' else: otype = 'European single' payoff_func = 'np.maximum(maturity_value - %5.3f, 0)' # random strike strike = np.random.randint(36, 40) underlying = sorted(risk_factors.keys())[(i + no) % no] name = '%d_option_pos_%d' % (i, strike) positions[name] = derivatives_position( name=name, quantity=np.random.randint(1, 10), underlyings=[underlying], mar_env=me_option, otype=otype, payoff_func=payoff_func % strike) .. code:: python # number of derivatives positions len(positions) .. parsed-literal:: 250 Portfolio Valuation ------------------- First, the derivatives portfolio with **sequential valuation**. .. code:: python port = derivatives_portfolio( name='portfolio', positions=positions, val_env=val_env, risk_factors=risk_factors, correlations=correlations, parallel=True) # sequential calculation .. code:: python port.val_env.get_list('cholesky_matrix') .. parsed-literal:: array([[ 1. , 0. , 0. , ..., 0. , 0. , 0. ], [ 0.1 , 0.99498744, 0. , ..., 0. , 0. , 0. ], [-0.1 , 0.01005038, 0.99493668, ..., 0. , 0. , 0. ], ..., [-0.1 , 0.01005038, -0.01015242, ..., 0.99239533, 0. , 0. ], [ 0. , 0. , 0. , ..., 0. , 1. , 0. ], [ 0.1 , -0.01005038, 0.01015242, ..., 0.01526762, 0. , 0.99227788]]) The call of the ``get_values`` method to **value all instruments**. .. code:: python %time res = port.get_statistics(fixed_seed=True) .. parsed-literal:: Totals pos_value 10327.477405 pos_delta 115.001400 pos_vega 8778.425900 dtype: float64 CPU times: user 849 ms, sys: 9.15 s, total: 10 s Wall time: 31.3 s .. code:: python res.set_index('position', inplace=False) .. raw:: html
name | quantity | otype | risk_facts | value | currency | pos_value | pos_delta | pos_vega | |
---|---|---|---|---|---|---|---|---|---|
position | |||||||||
94_option_pos_38 | 94_option_pos_38 | 9 | European single | [ 45_sv] | 11.689901 | EUR | 105.209109 | 6.5340 | 31.3659 |
184_option_pos_37 | 184_option_pos_37 | 3 | American single | [ 35_jd] | 2.659000 | EUR | 7.977000 | -0.4491 | 33.9000 |
187_option_pos_36 | 187_option_pos_36 | 1 | European single | [ 38_gbm] | 0.035181 | EUR | 0.035181 | 0.0215 | 1.2782 |
181_option_pos_38 | 181_option_pos_38 | 6 | European single | [ 32_jd] | 10.185577 | EUR | 61.113462 | 4.4790 | 57.4704 |
22_option_pos_38 | 22_option_pos_38 | 8 | American single | [ 23_jd] | 1.136000 | EUR | 9.088000 | -0.5248 | 64.0000 |
103_option_pos_36 | 103_option_pos_36 | 2 | European single | [ 4_gbm] | 0.068706 | EUR | 0.137412 | 0.1276 | 7.2696 |
201_option_pos_38 | 201_option_pos_38 | 3 | American single | [ 2_gbm] | 4.859000 | EUR | 14.577000 | -1.2135 | 42.9000 |
144_option_pos_39 | 144_option_pos_39 | 9 | European single | [ 45_sv] | 11.177332 | EUR | 100.595988 | 6.4188 | 31.9941 |
203_option_pos_38 | 203_option_pos_38 | 5 | European single | [ 4_gbm] | 0.019660 | EUR | 0.098300 | 0.1115 | 7.7775 |
155_option_pos_39 | 155_option_pos_39 | 5 | American single | [ 6_jd] | 15.146000 | EUR | 75.730000 | -4.0440 | 13.5000 |
146_option_pos_36 | 146_option_pos_36 | 3 | European single | [ 47_sv] | 2.894735 | EUR | 8.684205 | 1.2897 | 2.9382 |
46_option_pos_39 | 46_option_pos_39 | 2 | European single | [ 47_sv] | 2.200646 | EUR | 4.401292 | 0.7166 | 1.8760 |
34_option_pos_37 | 34_option_pos_37 | 9 | American single | [ 35_jd] | 2.659000 | EUR | 23.931000 | -1.3473 | 101.7000 |
188_option_pos_39 | 188_option_pos_39 | 8 | American single | [ 39_sv] | 9.770000 | EUR | 78.160000 | -3.9096 | 13.7800 |
222_option_pos_38 | 222_option_pos_38 | 4 | European single | [ 23_jd] | 22.837920 | EUR | 91.351680 | 3.5512 | 12.6368 |
159_option_pos_36 | 159_option_pos_36 | 9 | American single | [ 10_sv] | 7.882000 | EUR | 70.938000 | -4.1706 | 6.3000 |
217_option_pos_39 | 217_option_pos_39 | 4 | European single | [ 18_sv] | 13.021438 | EUR | 52.085752 | 3.0700 | 4.1216 |
137_option_pos_39 | 137_option_pos_39 | 6 | American single | [ 38_gbm] | 17.842000 | EUR | 107.052000 | -5.9940 | 0.6000 |
130_option_pos_37 | 130_option_pos_37 | 1 | European single | [ 31_sv] | 1.140401 | EUR | 1.140401 | 0.2380 | 1.2870 |
135_option_pos_38 | 135_option_pos_38 | 2 | European single | [ 36_gbm] | 18.964940 | EUR | 37.929880 | 1.7504 | 19.0952 |
190_option_pos_36 | 190_option_pos_36 | 7 | American single | [ 41_jd] | 5.429000 | EUR | 38.003000 | -2.7216 | 79.8000 |
109_option_pos_37 | 109_option_pos_37 | 5 | European single | [ 10_sv] | 3.839486 | EUR | 19.197430 | 2.4440 | 6.1185 |
191_option_pos_38 | 191_option_pos_38 | 9 | American single | [ 42_sv] | 7.267000 | EUR | 65.403000 | -3.6981 | 11.7000 |
164_option_pos_36 | 164_option_pos_36 | 4 | European single | [ 15_gbm] | 5.920606 | EUR | 23.682424 | 2.2248 | 55.3132 |
112_option_pos_37 | 112_option_pos_37 | 3 | European single | [ 13_sv] | 1.718209 | EUR | 5.154627 | 0.9345 | 1.9341 |
240_option_pos_36 | 240_option_pos_36 | 2 | American single | [ 41_jd] | 5.429000 | EUR | 10.858000 | -0.7776 | 22.8000 |
39_option_pos_38 | 39_option_pos_38 | 3 | European single | [ 40_jd] | 15.213182 | EUR | 45.639546 | 2.1216 | 35.8626 |
233_option_pos_37 | 233_option_pos_37 | 9 | American single | [ 34_jd] | 6.746000 | EUR | 60.714000 | -2.0925 | 129.9690 |
175_option_pos_39 | 175_option_pos_39 | 7 | American single | [ 26_gbm] | 3.204000 | EUR | 22.428000 | -1.2404 | 95.8629 |
37_option_pos_38 | 37_option_pos_38 | 2 | European single | [ 38_gbm] | 0.020348 | EUR | 0.040696 | 0.0252 | 1.6426 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
235_option_pos_37 | 235_option_pos_37 | 4 | American single | [ 36_gbm] | 0.820000 | EUR | 3.280000 | -0.2464 | 36.0000 |
11_option_pos_38 | 11_option_pos_38 | 1 | European single | [ 12_jd] | 1.310847 | EUR | 1.310847 | 0.2786 | 8.6502 |
15_option_pos_37 | 15_option_pos_37 | 5 | European single | [ 16_gbm] | 1.684895 | EUR | 8.424475 | 1.5800 | 53.0640 |
162_option_pos_37 | 162_option_pos_37 | 9 | American single | [ 13_sv] | 11.671000 | EUR | 105.039000 | -6.5502 | 39.6000 |
179_option_pos_39 | 179_option_pos_39 | 2 | European single | [ 30_gbm] | 12.171664 | EUR | 24.343328 | 1.3514 | 29.9058 |
104_option_pos_36 | 104_option_pos_36 | 2 | American single | [ 5_gbm] | 3.937000 | EUR | 7.874000 | -0.4282 | 27.1214 |
31_option_pos_38 | 31_option_pos_38 | 9 | European single | [ 32_jd] | 10.185577 | EUR | 91.670193 | 6.7185 | 86.2056 |
96_option_pos_36 | 96_option_pos_36 | 3 | American single | [ 47_sv] | 9.187000 | EUR | 27.561000 | -1.7361 | 4.5000 |
19_option_pos_36 | 19_option_pos_36 | 8 | American single | [ 20_jd] | 12.316000 | EUR | 98.528000 | -8.0000 | 13.6000 |
87_option_pos_36 | 87_option_pos_36 | 6 | American single | [ 38_gbm] | 14.845000 | EUR | 89.070000 | -5.9514 | -3.6000 |
121_option_pos_36 | 121_option_pos_36 | 7 | European single | [ 22_sv] | 8.149622 | EUR | 57.047354 | 4.6865 | 19.7043 |
200_option_pos_37 | 200_option_pos_37 | 8 | European single | [ 1_sv] | 7.251997 | EUR | 58.015976 | 4.9464 | 29.2368 |
99_option_pos_36 | 99_option_pos_36 | 4 | European single | [ 50_gbm] | 7.058561 | EUR | 28.234244 | 2.5984 | 52.8508 |
53_option_pos_37 | 53_option_pos_37 | 3 | European single | [ 4_gbm] | 0.037188 | EUR | 0.111564 | 0.1203 | 7.5129 |
111_option_pos_37 | 111_option_pos_37 | 4 | American single | [ 12_jd] | 11.090000 | EUR | 44.360000 | -2.9284 | 43.2000 |
204_option_pos_36 | 204_option_pos_36 | 1 | American single | [ 5_gbm] | 3.937000 | EUR | 3.937000 | -0.2141 | 13.5607 |
81_option_pos_36 | 81_option_pos_36 | 3 | European single | [ 32_jd] | 11.396591 | EUR | 34.189773 | 2.3433 | 25.3110 |
246_option_pos_37 | 246_option_pos_37 | 4 | European single | [ 47_sv] | 2.644399 | EUR | 10.577596 | 1.6224 | 3.8472 |
147_option_pos_36 | 147_option_pos_36 | 1 | American single | [ 48_sv] | 9.179000 | EUR | 9.179000 | -0.5690 | 0.7000 |
243_option_pos_38 | 243_option_pos_38 | 5 | American single | [ 44_jd] | 4.452000 | EUR | 22.260000 | -1.0335 | 72.5000 |
83_option_pos_39 | 83_option_pos_39 | 8 | American single | [ 34_jd] | 7.775000 | EUR | 62.200000 | -2.1904 | 118.8864 |
75_option_pos_39 | 75_option_pos_39 | 6 | European single | [ 26_gbm] | 24.214688 | EUR | 145.288128 | 4.9746 | 90.0108 |
234_option_pos_37 | 234_option_pos_37 | 6 | American single | [ 35_jd] | 2.659000 | EUR | 15.954000 | -0.8982 | 67.8000 |
163_option_pos_37 | 163_option_pos_37 | 5 | European single | [ 14_jd] | 21.499076 | EUR | 107.495380 | 3.9800 | 55.7650 |
49_option_pos_37 | 49_option_pos_37 | 4 | American single | [ 50_gbm] | 4.377000 | EUR | 17.508000 | -1.4884 | 62.0000 |
110_option_pos_36 | 110_option_pos_36 | 5 | American single | [ 11_jd] | 2.080000 | EUR | 10.400000 | -0.7460 | 40.5000 |
228_option_pos_38 | 228_option_pos_38 | 3 | European single | [ 29_jd] | 23.634880 | EUR | 70.904640 | 2.5209 | 28.7898 |
118_option_pos_37 | 118_option_pos_37 | 8 | American single | [ 19_gbm] | 6.387000 | EUR | 51.096000 | -2.0376 | 122.3936 |
150_option_pos_36 | 150_option_pos_36 | 8 | American single | [ 1_sv] | 7.070000 | EUR | 56.560000 | -2.9960 | 26.9624 |
124_option_pos_38 | 124_option_pos_38 | 1 | European single | [ 25_jd] | 11.170898 | EUR | 11.170898 | 0.8039 | 6.6341 |
250 rows × 9 columns
0 | |
---|---|
count | 2500.000000 |
mean | 10327.480869 |
std | 2151.707101 |
min | 4691.853004 |
25% | 8781.364261 |
50% | 10122.550615 |
75% | 11584.503917 |
max | 20911.950046 |