<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <img src="http
Step1:  There are the following multiple risk factor valuation classes available
Step2:  We assum a positive correlation between the two risk factors.
Step3:  Valuation Environment
Similar to the instantiation of a derivatives_portfolio object, a valuation environment is needed (unifying certain parameters/assumptions for all relevant risk factors of a derivative).
Step4:  valuation_mcs_european_multi
As an example for a multi-risk derivative with European exercise consider a maximum call option. With multiple risk factors, payoff functions are defined by adding key (the name strings) to the maturity_value array object. As with the portfolio valuation class, the multi-risk factor valuation classes get passed market_environment objects only and not the risk factor model objects themsemselves.
Step5:  At instantiation, the respective risk factor model objects are instantiated as well.
Step6:  Correlations are stored as well and the resulting corrleation and Cholesky matrices are generated.
Step7:  The payoff of a European option is a one-dimensional ndarray object.
Step8:  Present value estimations are generated by a call of the present_value method.
Step9:  The update method allows updating of certain parameters.
Step10:  Let us reset the values to the original parameters.
Step11:  When calculating Greeks the risk factor now has to be specified by providing its name.
Step12:  Sensitivities Positive Correlation
Almos in complete analogy to the single-risk valuation classes, sensitivities can be estimated for the multi-risk valuation classes. 
Sensitivities Risk Factor 1
Consider first the case from before with positive correlation between the two risk factors. The following estimates and plots the sensitivities for the first risk factor gbm1.
Step13:  Sensitivities Risk Factor 2
Now the sensitivities for the second risk factor.
Step14:  Sensitivities with Negative Correlation
The second case is for highly negatively correlated risk factors.
Step15:  Sensitivities Risk Factor 1
Again, sensitivities for the first risk factor first.
Step16:  Sensitivities Risk Factor 2
Finally, the sensitivities for the second risk factor for this second scenario.
Step17:  Surfaces for Positive Correlation Case
Let us return to the case of positive correlation between the two relevant risk factors.
Step18:  Value Surface
We are now interested in the value surface of the derivative instrument for both different initial values of the first and second risk factor.
Step19:  The following estimates for all possible combinations of the initial values---given the assumptions from above---the present value of the European maximum call option.
Step20:  The resulting plot then looks as follows. Here, a helper plot function of DX Analytics is used.
Step21:  Delta Surfaces
Applying a very similar approach, a delta surface for all possible combinations of the intial values is as easily generated.
Step22:  The plot for the delta surface of the first risk factor.
Step23:  And the plot for the delta of the second risk factor.
Step24:  Vega Surfaces
The same approach can of course be applied to generate vega surfaces.
Step25:  The surface for the first risk factor.
Step26:  And the one for the second risk factor.
Step27:  Finally, we reset the intial values and the volatilities for the two risk factors.
Step28:  valuation_mcs_american_multi
In general, the modeling and handling of the valuation classes for American exercise is not too different from those for European exercise. The major difference is in the definition of payoff function.
Present Values
This example models an American minimum put on the two risk factors from before.
Step29:  The present value surface is generated in the same way as before for the European option on the two risk factors. The computational burden is of course much higher for the American option, which are valued by the use of the Least-Squares Monte Carlo approach (LSM) according to Longstaff-Schwartz (2001).
Step30:  Delta Surfaces
The same exercise as before for the two delta surfaces.
Step31:  Vega Surfaces
And finally for the vega surfaces.
Step32:  More than Two Risk Factors
The principles of working with multi-risk valuation classes can be illustrated quite well in the two risk factor case. However, there is---in theory---no limitation on the number of risk factors used for derivatives modeling.
Four Asset Basket Option
Consider a maximum basket option on four different risk factors. We add a jump diffusion as well as a stochastic volatility model to the mix
Step33:  In this case, we need to specify three correlation values.
Step34:  The payoff function in this case gets a bit more complex.
Step35:  However, the instantiation of the valuation classe remains the same.
Step36:  Example Output and Calculations
The following just displays some example output and the results from certain calculations.
Step37:  The correlation and Cholesky matrices now are of shape 4x4.
Step38:  Delta and vega estimates are generated in exactly the same fashion as in the two risk factor case.
Step39:  Delta for Jump Diffusion and Stochastic Vol Process
Of course, we cannot visualize Greek surfaces dependent on initial values for all four risk factors but still for two. In what follows we generate the delta surfaces with respect to the jump diffusion- and stochastic volatility-based risk factors.
Step40:  Vega for Jump Diffusion and Stochastic Vol Process
Now the same exercise for the vega surfaces for the same two risk factors.
Step41:  American Exercise
As a final illustration consider the case of an American minimum put option on the four risk factors. This again is a step that leads to a much increased computational burden due to the necessity to apply the least-squares regression approach.
Step42:  However, another illustration that even such a complex instrument can be handled as elegantly as the most simple one (i.e. European option on single risk factor). Let us compare the present value estimates for both the European and American maximum basket options.
<ASSISTANT_TASK:>
Python Code:
from dx import *
import seaborn as sns; sns.set()
import time
t0 = time.time()
Explanation: <img src="http://hilpisch.com/tpq_logo.png" alt="The Python Quants" width="45%" align="right" border="4">
Multi-Risk Derivatives Valuation
A specialty of DX Analytics is the valuation of derivatives instruments defined on multiple risk factors and portfolios composed of such derivatives. This section of the documentation illustrates the usage of the dedicated multi-risk valuation classes.
End of explanation
r = constant_short_rate('r', 0.06)
me1 = market_environment('me1', dt.datetime(2015, 1, 1))
me2 = market_environment('me2', dt.datetime(2015, 1, 1))
me1.add_constant('initial_value', 36.)
me1.add_constant('volatility', 0.1)  # low volatility
me1.add_constant('currency', 'EUR')
me1.add_constant('model', 'gbm')
me2.add_environment(me1)
me2.add_constant('initial_value', 36.)
me2.add_constant('volatility', 0.5)  # high volatility
Explanation: There are the following multiple risk factor valuation classes available:
valuation_mcs_european_multi for the valuation of multi-risk derivatives with European exercise
valuation_mcs_american_multi for the valuation of multi-risk derivatives with American exercise
The handling of these classes is similar to building a portfolio of single-risk derivatives positions.
Market Environments
Market environments for the risk factors are the starting point.
End of explanation
risk_factors = {'gbm1' : me1, 'gbm2' : me2}
correlations = [['gbm1', 'gbm2', 0.5]]
Explanation: We assum a positive correlation between the two risk factors.
End of explanation
val_env = market_environment('val_env', dt.datetime(2015, 1, 1))
val_env.add_constant('starting_date', val_env.pricing_date)
val_env.add_constant('final_date', dt.datetime(2015, 12, 31))
val_env.add_constant('frequency', 'W')
val_env.add_constant('paths', 5000)
val_env.add_curve('discount_curve', r)
val_env.add_constant('maturity', dt.datetime(2015, 12, 31))
val_env.add_constant('currency', 'EUR')
Explanation: Valuation Environment
Similar to the instantiation of a derivatives_portfolio object, a valuation environment is needed (unifying certain parameters/assumptions for all relevant risk factors of a derivative).
End of explanation
# European maximum call option
payoff_func = "np.maximum(np.maximum(maturity_value['gbm1'], maturity_value['gbm2']) - 38, 0)"
vc = valuation_mcs_european_multi(
            name='European maximum call',  # name
            val_env=val_env,  # valuation environment
            risk_factors=risk_factors,  # the relevant risk factors
            correlations=correlations,  # correlations between risk factors
            payoff_func=payoff_func)  # payoff function
vc.risk_factors
Explanation: valuation_mcs_european_multi
As an example for a multi-risk derivative with European exercise consider a maximum call option. With multiple risk factors, payoff functions are defined by adding key (the name strings) to the maturity_value array object. As with the portfolio valuation class, the multi-risk factor valuation classes get passed market_environment objects only and not the risk factor model objects themsemselves.
End of explanation
vc.underlying_objects
Explanation: At instantiation, the respective risk factor model objects are instantiated as well.
End of explanation
vc.correlations
vc.correlation_matrix
vc.val_env.get_list('cholesky_matrix')
Explanation: Correlations are stored as well and the resulting corrleation and Cholesky matrices are generated.
End of explanation
np.shape(vc.generate_payoff())
Explanation: The payoff of a European option is a one-dimensional ndarray object.
End of explanation
vc.present_value()
Explanation: Present value estimations are generated by a call of the present_value method.
End of explanation
vc.update('gbm1', initial_value=50.)
vc.present_value()
vc.update('gbm2', volatility=0.6)
vc.present_value()
Explanation: The update method allows updating of certain parameters.
End of explanation
vc.update('gbm1', initial_value=36., volatility=0.1)
vc.update('gbm2', initial_value=36., volatility=0.5)
Explanation: Let us reset the values to the original parameters.
End of explanation
vc.delta('gbm2', interval=0.5)
vc.vega('gbm1')
Explanation: When calculating Greeks the risk factor now has to be specified by providing its name.
End of explanation
%%time
s_list = np.arange(28., 46.1, 2.)
pv = []; de = []; ve = []
for s in s_list:
    vc.update('gbm1', initial_value=s)
    pv.append(vc.present_value())
    de.append(vc.delta('gbm1', .5))
    ve.append(vc.vega('gbm1', 0.2))
vc.update('gbm1', initial_value=36.)
%matplotlib inline
plot_option_stats(s_list, pv, de, ve)
Explanation: Sensitivities Positive Correlation
Almos in complete analogy to the single-risk valuation classes, sensitivities can be estimated for the multi-risk valuation classes. 
Sensitivities Risk Factor 1
Consider first the case from before with positive correlation between the two risk factors. The following estimates and plots the sensitivities for the first risk factor gbm1.
End of explanation
%%time
s_list = np.arange(28., 46.1, 2.)
pv = []; de = []; ve = []
for s in s_list:
    vc.update('gbm2', initial_value=s)
    pv.append(vc.present_value())
    de.append(vc.delta('gbm2', .5))
    ve.append(vc.vega('gbm2', 0.2))
plot_option_stats(s_list, pv, de, ve)
Explanation: Sensitivities Risk Factor 2
Now the sensitivities for the second risk factor.
End of explanation
correlations = [['gbm1', 'gbm2', -0.9]]
# European maximum call option
payoff_func = "np.maximum(np.maximum(maturity_value['gbm1'], maturity_value['gbm2']) - 38, 0)"
vc = valuation_mcs_european_multi(
            name='European maximum call',
            val_env=val_env,
            risk_factors=risk_factors,
            correlations=correlations,
            payoff_func=payoff_func)
Explanation: Sensitivities with Negative Correlation
The second case is for highly negatively correlated risk factors.
End of explanation
%%time
s_list = np.arange(28., 46.1, 2.)
pv = []; de = []; ve = []
for s in s_list:
    vc.update('gbm1', initial_value=s)
    pv.append(vc.present_value())
    de.append(vc.delta('gbm1', .5))
    ve.append(vc.vega('gbm1', 0.2))
vc.update('gbm1', initial_value=36.)
plot_option_stats(s_list, pv, de, ve)
Explanation: Sensitivities Risk Factor 1
Again, sensitivities for the first risk factor first.
End of explanation
%%time
s_list = np.arange(28., 46.1, 2.)
pv = []; de = []; ve = []
for s in s_list:
    vc.update('gbm2', initial_value=s)
    pv.append(vc.present_value())
    de.append(vc.delta('gbm2', .5))
    ve.append(vc.vega('gbm2', 0.2))
plot_option_stats(s_list, pv, de, ve)
Explanation: Sensitivities Risk Factor 2
Finally, the sensitivities for the second risk factor for this second scenario.
End of explanation
correlations = [['gbm1', 'gbm2', 0.5]]
# European maximum call option
payoff_func = "np.maximum(np.maximum(maturity_value['gbm1'], maturity_value['gbm2']) - 38, 0)"
vc = valuation_mcs_european_multi(
            name='European maximum call',
            val_env=val_env,
            risk_factors=risk_factors,
            correlations=correlations,
            payoff_func=payoff_func)
Explanation: Surfaces for Positive Correlation Case
Let us return to the case of positive correlation between the two relevant risk factors.
End of explanation
asset_1 = np.arange(28., 46.1, 4.)  # range of initial values
asset_2 = asset_1
a_1, a_2 = np.meshgrid(asset_1, asset_2)
  # two-dimensional grids out of the value vectors
value = np.zeros_like(a_1)
Explanation: Value Surface
We are now interested in the value surface of the derivative instrument for both different initial values of the first and second risk factor.
End of explanation
%%time
for i in range(np.shape(value)[0]):
    for j in range(np.shape(value)[1]):
        vc.update('gbm1', initial_value=a_1[i, j])
        vc.update('gbm2', initial_value=a_2[i, j])
        value[i, j] = vc.present_value()
Explanation: The following estimates for all possible combinations of the initial values---given the assumptions from above---the present value of the European maximum call option.
End of explanation
plot_greeks_3d([a_1, a_2, value], ['gbm1', 'gbm2', 'present value'])
Explanation: The resulting plot then looks as follows. Here, a helper plot function of DX Analytics is used.
End of explanation
delta_1 = np.zeros_like(a_1)
delta_2 = np.zeros_like(a_1)
%%time
for i in range(np.shape(delta_1)[0]):
    for j in range(np.shape(delta_1)[1]):
        vc.update('gbm1', initial_value=a_1[i, j])
        vc.update('gbm2', initial_value=a_2[i, j])
        delta_1[i, j] = vc.delta('gbm1')
        delta_2[i, j] = vc.delta('gbm2')
Explanation: Delta Surfaces
Applying a very similar approach, a delta surface for all possible combinations of the intial values is as easily generated.
End of explanation
plot_greeks_3d([a_1, a_2, delta_1], ['gbm1', 'gbm2', 'delta gbm1'])
Explanation: The plot for the delta surface of the first risk factor.
End of explanation
plot_greeks_3d([a_1, a_2, delta_2], ['gbm1', 'gbm2', 'delta gbm2'])
Explanation: And the plot for the delta of the second risk factor.
End of explanation
vega_1 = np.zeros_like(a_1)
vega_2 = np.zeros_like(a_1)
for i in range(np.shape(vega_1)[0]):
    for j in range(np.shape(vega_1)[1]):
        vc.update('gbm1', initial_value=a_1[i, j])
        vc.update('gbm2', initial_value=a_2[i, j])
        vega_1[i, j] = vc.vega('gbm1')
        vega_2[i, j] = vc.vega('gbm2')
Explanation: Vega Surfaces
The same approach can of course be applied to generate vega surfaces.
End of explanation
plot_greeks_3d([a_1, a_2, vega_1], ['gbm1', 'gbm2', 'vega gbm1'])
Explanation: The surface for the first risk factor.
End of explanation
plot_greeks_3d([a_1, a_2, vega_2], ['gbm1', 'gbm2', 'vega gbm2'])
Explanation: And the one for the second risk factor.
End of explanation
# restore initial values
vc.update('gbm1', initial_value=36., volatility=0.1)
vc.update('gbm2', initial_value=36., volatility=0.5)
Explanation: Finally, we reset the intial values and the volatilities for the two risk factors.
End of explanation
# American put payoff
payoff_am = "np.maximum(34 - np.minimum(instrument_values['gbm1'], instrument_values['gbm2']), 0)"
# finer time grid and more paths
val_env.add_constant('frequency', 'B')
val_env.add_curve('time_grid', None)
  # delete existing time grid information
val_env.add_constant('paths', 5000)
# American put option on minimum of two assets
vca = valuation_mcs_american_multi(
            name='American minimum put',
            val_env=val_env,
            risk_factors=risk_factors,
            correlations=correlations,
            payoff_func=payoff_am)
vca.present_value()
for key, obj in vca.instrument_values.items():
    print np.shape(vca.instrument_values[key])
Explanation: valuation_mcs_american_multi
In general, the modeling and handling of the valuation classes for American exercise is not too different from those for European exercise. The major difference is in the definition of payoff function.
Present Values
This example models an American minimum put on the two risk factors from before.
End of explanation
asset_1 = np.arange(28., 44.1, 4.)
asset_2 = asset_1
a_1, a_2 = np.meshgrid(asset_1, asset_2)
value = np.zeros_like(a_1)
%%time
for i in range(np.shape(value)[0]):
    for j in range(np.shape(value)[1]):
        vca.update('gbm1', initial_value=a_1[i, j])
        vca.update('gbm2', initial_value=a_2[i, j])
        value[i, j] = vca.present_value()
plot_greeks_3d([a_1, a_2, value], ['gbm1', 'gbm2', 'present value'])
Explanation: The present value surface is generated in the same way as before for the European option on the two risk factors. The computational burden is of course much higher for the American option, which are valued by the use of the Least-Squares Monte Carlo approach (LSM) according to Longstaff-Schwartz (2001).
End of explanation
delta_1 = np.zeros_like(a_1)
delta_2 = np.zeros_like(a_1)
%%time
for i in range(np.shape(delta_1)[0]):
    for j in range(np.shape(delta_1)[1]):
        vca.update('gbm1', initial_value=a_1[i, j])
        vca.update('gbm2', initial_value=a_2[i, j])
        delta_1[i, j] = vca.delta('gbm1')
        delta_2[i, j] = vca.delta('gbm2')
plot_greeks_3d([a_1, a_2, delta_1], ['gbm1', 'gbm2', 'delta gbm1'])
plot_greeks_3d([a_1, a_2, delta_2], ['gbm1', 'gbm2', 'delta gbm2'])
Explanation: Delta Surfaces
The same exercise as before for the two delta surfaces.
End of explanation
vega_1 = np.zeros_like(a_1)
vega_2 = np.zeros_like(a_1)
%%time
for i in range(np.shape(vega_1)[0]):
    for j in range(np.shape(vega_1)[1]):
        vca.update('gbm1', initial_value=a_1[i, j])
        vca.update('gbm2', initial_value=a_2[i, j])
        vega_1[i, j] = vca.vega('gbm1')
        vega_2[i, j] = vca.vega('gbm2')
plot_greeks_3d([a_1, a_2, vega_1], ['gbm1', 'gbm2', 'vega gbm1'])
plot_greeks_3d([a_1, a_2, vega_2], ['gbm1', 'gbm2', 'vega gbm2'])
Explanation: Vega Surfaces
And finally for the vega surfaces.
End of explanation
me3 = market_environment('me3', dt.datetime(2015, 1, 1))
me4 = market_environment('me4', dt.datetime(2015, 1, 1))
me3.add_environment(me1)
me4.add_environment(me1)
# for jump-diffusion
me3.add_constant('lambda', 0.5)
me3.add_constant('mu', -0.6)
me3.add_constant('delta', 0.1)
me3.add_constant('model', 'jd')
# for stoch volatility model
me4.add_constant('kappa', 2.0)
me4.add_constant('theta', 0.3)
me4.add_constant('vol_vol', 0.2)
me4.add_constant('rho', -0.75)
me4.add_constant('model', 'sv')
val_env.add_constant('paths', 10000)
val_env.add_constant('frequency', 'W')
val_env.add_curve('time_grid', None)
Explanation: More than Two Risk Factors
The principles of working with multi-risk valuation classes can be illustrated quite well in the two risk factor case. However, there is---in theory---no limitation on the number of risk factors used for derivatives modeling.
Four Asset Basket Option
Consider a maximum basket option on four different risk factors. We add a jump diffusion as well as a stochastic volatility model to the mix
End of explanation
risk_factors = {'gbm1' : me1, 'gbm2' : me2, 'jd' : me3, 'sv' : me4}
correlations = [['gbm1', 'gbm2', 0.5], ['gbm2', 'jd', -0.5], ['gbm1', 'sv', 0.7]]
Explanation: In this case, we need to specify three correlation values.
End of explanation
# European maximum call payoff
payoff_1 = "np.maximum(np.maximum(np.maximum(maturity_value['gbm1'], maturity_value['gbm2']),"
payoff_2 = " np.maximum(maturity_value['jd'], maturity_value['sv'])) - 40, 0)"
payoff = payoff_1 + payoff_2
payoff
Explanation: The payoff function in this case gets a bit more complex.
End of explanation
vc = valuation_mcs_european_multi(
            name='European maximum call',
            val_env=val_env,
            risk_factors=risk_factors,
            correlations=correlations,
            payoff_func=payoff)
Explanation: However, the instantiation of the valuation classe remains the same.
End of explanation
vc.risk_factors
vc.underlying_objects
vc.present_value()
Explanation: Example Output and Calculations
The following just displays some example output and the results from certain calculations.
End of explanation
vc.correlation_matrix
vc.val_env.get_list('cholesky_matrix')
Explanation: The correlation and Cholesky matrices now are of shape 4x4.
End of explanation
vc.delta('jd', interval=0.1)
vc.delta('sv')
vc.vega('jd')
vc.vega('sv')
Explanation: Delta and vega estimates are generated in exactly the same fashion as in the two risk factor case.
End of explanation
delta_1 = np.zeros_like(a_1)
delta_2 = np.zeros_like(a_1)
%%time
for i in range(np.shape(delta_1)[0]):
    for j in range(np.shape(delta_1)[1]):
        vc.update('jd', initial_value=a_1[i, j])
        vc.update('sv', initial_value=a_2[i, j])
        delta_1[i, j] = vc.delta('jd')
        delta_2[i, j] = vc.delta('sv')
plot_greeks_3d([a_1, a_2, delta_1], ['jump diffusion', 'stochastic vol', 'delta jd'])
plot_greeks_3d([a_1, a_2, delta_2], ['jump diffusion', 'stochastic vol', 'delta sv'])
Explanation: Delta for Jump Diffusion and Stochastic Vol Process
Of course, we cannot visualize Greek surfaces dependent on initial values for all four risk factors but still for two. In what follows we generate the delta surfaces with respect to the jump diffusion- and stochastic volatility-based risk factors.
End of explanation
vega_1 = np.zeros_like(a_1)
vega_2 = np.zeros_like(a_1)
%%time
for i in range(np.shape(vega_1)[0]):
    for j in range(np.shape(vega_1)[1]):
        vc.update('jd', initial_value=a_1[i, j])
        vc.update('sv', initial_value=a_2[i, j])
        vega_1[i, j] = vc.vega('jd')
        vega_2[i, j] = vc.vega('sv')
plot_greeks_3d([a_1, a_2, vega_1], ['jump diffusion', 'stochastic vol', 'vega jd'])
plot_greeks_3d([a_1, a_2, vega_2], ['jump diffusion', 'stochastic vol', 'vega sv'])
Explanation: Vega for Jump Diffusion and Stochastic Vol Process
Now the same exercise for the vega surfaces for the same two risk factors.
End of explanation
# payoff of American minimum put option
payoff_am_1 = "np.maximum(40 - np.minimum(np.minimum(instrument_values['gbm1'], instrument_values['gbm2']),"
payoff_am_2 = "np.minimum(instrument_values['jd'], instrument_values['sv'])), 0)"
payoff_am = payoff_am_1 + payoff_am_2
vca = valuation_mcs_american_multi(
            name='American minimum put',
            val_env=val_env,
            risk_factors=risk_factors,
            correlations=correlations,
            payoff_func=payoff_am)
Explanation: American Exercise
As a final illustration consider the case of an American minimum put option on the four risk factors. This again is a step that leads to a much increased computational burden due to the necessity to apply the least-squares regression approach.
End of explanation
# restore initial values
vc.update('jd', initial_value=36., volatility=0.1)
vc.update('sv', initial_value=36., volatility=0.1)
%time vc.present_value()
%time vca.present_value()
%time vca.delta('gbm1')
%time vca.delta('gbm2')
%time vca.vega('jd')
%time vca.vega('sv')
print "Duration for whole notebook %.2f in min" % ((time.time() - t0) / 60)
Explanation: However, another illustration that even such a complex instrument can be handled as elegantly as the most simple one (i.e. European option on single risk factor). Let us compare the present value estimates for both the European and American maximum basket options.
End of explanation
<END_TASK>