#!/usr/bin/env python
# coding: utf-8
#
# # Quickstart
# This brief first part illustrates---without much explanation---the usage of the DX Analytics library. It models two risk factors, two derivatives instruments and values these in a portfolio context.
# In[1]:
import dx
import datetime as dt
import pandas as pd
from pylab import plt
plt.style.use('seaborn')
# ## Risk Factor Models
# The first step is to define a **model for the risk-neutral discounting**.
# In[2]:
r = dx.constant_short_rate('r', 0.01)
# We then define a **market environment** containing the major parameter specifications needed,
# In[3]:
me_1 = dx.market_environment('me', dt.datetime(2016, 1, 1))
# In[4]:
me_1.add_constant('initial_value', 100.)
# starting value of simulated processes
me_1.add_constant('volatility', 0.2)
# volatiltiy factor
me_1.add_constant('final_date', dt.datetime(2017, 6, 30))
# horizon for simulation
me_1.add_constant('currency', 'EUR')
# currency of instrument
me_1.add_constant('frequency', 'W')
# frequency for discretization
me_1.add_constant('paths', 10000)
# number of paths
me_1.add_curve('discount_curve', r)
# number of paths
# Next, the model object for the **first risk factor**, based on the geometric Brownian motion (Black-Scholes-Merton (1973) model).
# In[5]:
gbm_1 = dx.geometric_brownian_motion('gbm_1', me_1)
# Some paths visualized.
# In[6]:
pdf = pd.DataFrame(gbm_1.get_instrument_values(), index=gbm_1.time_grid)
# In[7]:
get_ipython().run_line_magic('matplotlib', 'inline')
pdf.iloc[:, :10].plot(legend=False, figsize=(10, 6));
# **Second risk factor** with higher volatility. We overwrite the respective value in the market environment.
# In[8]:
me_2 = dx.market_environment('me_2', me_1.pricing_date)
me_2.add_environment(me_1) # add complete environment
me_2.add_constant('volatility', 0.5) # overwrite value
# In[9]:
gbm_2 = dx.geometric_brownian_motion('gbm_2', me_2)
# In[10]:
pdf = pd.DataFrame(gbm_2.get_instrument_values(), index=gbm_2.time_grid)
# In[11]:
pdf.iloc[:, :10].plot(legend=False, figsize=(10, 6));
# ## Valuation Models
# Based on the risk factors, we can then define derivatives models for valuation. To this end, we need to add at least one (the `maturity`), in general two (`maturity` and `strike`), parameters to the market environments.
# In[12]:
me_opt = dx.market_environment('me_opt', me_1.pricing_date)
me_opt.add_environment(me_1)
me_opt.add_constant('maturity', dt.datetime(2017, 6, 30))
me_opt.add_constant('strike', 110.)
# The first derivative is an **American put option** on the first risk factor `gbm_1`.
# In[13]:
am_put = dx.valuation_mcs_american_single(
name='am_put',
underlying=gbm_1,
mar_env=me_opt,
payoff_func='np.maximum(strike - instrument_values, 0)')
# Let us calculate a **Monte Carlo present value estimate** and estimates for the option **Greeks**.
# In[14]:
am_put.present_value()
# In[15]:
am_put.delta()
# In[16]:
am_put.gamma()
# In[17]:
am_put.vega()
# In[18]:
am_put.theta()
# In[19]:
am_put.rho()
# The second derivative is a **European call option** on the second risk factor `gbm_2`.
# In[20]:
eur_call = dx.valuation_mcs_european_single(
name='eur_call',
underlying=gbm_2,
mar_env=me_opt,
payoff_func='np.maximum(maturity_value - strike, 0)')
# Valuation and Greek estimation for this option.
# In[21]:
eur_call.present_value()
# In[22]:
eur_call.delta()
# In[23]:
eur_call.gamma()
# In[24]:
eur_call.vega()
# In[25]:
eur_call.theta()
# In[26]:
eur_call.rho()
# ## Excursion: SABR Model
# To illustrate how general the approach of DX Analytics is, let us quickly analyze an option based on a SABR stochastic volatility process. In what follows herafter, the SABR model does not play a role.
#
# We need to define different parameters obviously.
# In[27]:
me_3 = dx.market_environment('me_3', me_1.pricing_date)
me_3.add_environment(me_1) # add complete environment
# In[28]:
# interest rate like parmeters
me_3.add_constant('initial_value', 0.05)
# initial value
me_3.add_constant('alpha', 0.1)
# initial variance
me_3.add_constant('beta', 0.5)
# exponent
me_3.add_constant('rho', 0.1)
# correlation factor
me_3.add_constant('vol_vol', 0.5)
# volatility of volatility/variance
# The model object instantiation.
# In[29]:
sabr = dx.sabr_stochastic_volatility('sabr', me_3)
# The valuation object instantiation.
# In[30]:
me_opt.add_constant('strike', me_3.get_constant('initial_value'))
# In[31]:
sabr_call = dx.valuation_mcs_european_single(
name='sabr_call',
underlying=sabr,
mar_env=me_opt,
payoff_func='np.maximum(maturity_value - strike, 0)')
# Some statistics --- same syntax/API even if the model is more complex.
# In[32]:
sabr_call.present_value(fixed_seed=True)
# In[33]:
sabr_call.delta()
# In[34]:
sabr_call.rho()
# In[35]:
# resetting the option strike
me_opt.add_constant('strike', 110.)
# ## Options Portfolio
# ### Modeling
# In a portfolio context, we need to add **information about the model class(es)** to be used to the market environments of the risk factors.
# In[36]:
me_1.add_constant('model', 'gbm')
me_2.add_constant('model', 'gbm')
# To compose a portfolio consisting of our just defined options, we need to define **derivatives positions**. Note that this step is *independent* from the risk factor model and option model definitions. We only use the market environment data and some additional information needed (e.g. payoff functions).
# In[37]:
put = dx.derivatives_position(
name='put',
quantity=2,
underlyings=['gbm_1'],
mar_env=me_opt,
otype='American single',
payoff_func='np.maximum(strike - instrument_values, 0)')
# In[38]:
call = dx.derivatives_position(
name='call',
quantity=3,
underlyings=['gbm_2'],
mar_env=me_opt,
otype='European single',
payoff_func='np.maximum(maturity_value - strike, 0)')
# Let us define the **relevant market** by 2 Python dictionaries, the correlation between the two risk factors and a valuation environment.
# In[39]:
risk_factors = {'gbm_1': me_1, 'gbm_2' : me_2}
correlations = [['gbm_1', 'gbm_2', -0.4]]
positions = {'put' : put, 'call' : call}
# In[40]:
val_env = dx.market_environment('general', dt.datetime(2016, 1, 1))
val_env.add_constant('frequency', 'W')
val_env.add_constant('paths', 10000)
val_env.add_constant('starting_date', val_env.pricing_date)
val_env.add_constant('final_date', val_env.pricing_date)
val_env.add_curve('discount_curve', r)
# These are used to define the **derivatives portfolio**.
# In[41]:
port = dx.derivatives_portfolio(
name='portfolio', # name
positions=positions, # derivatives positions
val_env=val_env, # valuation environment
risk_factors=risk_factors, # relevant risk factors
correlations=correlations, # correlation between risk factors
parallel=False) # parallel valuation
# ### Simulation and Valuation
# Now, we can get the **position values for the portfolio** via the `get_values` method.
# In[42]:
port.get_values()
# Via the `get_statistics` methods delta and vega values are provided as well.
# In[43]:
port.get_statistics()
# Much more complex scenarios are possible with DX Analytics
# ### Risk Reports
# Having modeled the derivatives portfolio, **risk reports** are only two method calls away.
# In[44]:
deltas, benchvalue = port.get_port_risk(Greek='Delta')
# In[45]:
deltas
# In[46]:
deltas.loc(axis=0)[:, 'value'] - benchvalue
# In[47]:
vegas, benchvalue = port.get_port_risk(Greek='Vega', step=0.05)
# In[48]:
vegas
# In[49]:
vegas.loc(axis=0)[:, 'value'] - benchvalue
# **Copyright, License & Disclaimer**
#
# © Dr. Yves J. Hilpisch | The Python Quants GmbH
#
# DX Analytics (the "dx library" or "dx package") 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 | [dx@tpq.io](mailto:team@tpq.io) |
# http://twitter.com/dyjh
#
#
#
# **Quant Platform** | http://pqp.io
#
# **Python for Finance Training** | http://training.tpq.io
#
# **Certificate in Computational Finance** | http://compfinance.tpq.io
#
# **Derivatives Analytics with Python (Wiley Finance)** |
# http://dawp.tpq.io
#
# **Python for Finance (2nd ed., O'Reilly)** |
# http://py4fi.tpq.io