from DX_connect import *
print info()
import os
os.environ['DX_USER']
On the Python Quant Platform you can do any kind of financial analytics with Python.
import pandas.io.data as web
AAPL = web.DataReader('AAPL', data_source='google')
%matplotlib inline
AAPL['Close'].plot()
Currently you implement many different applications by using the DEXISION Web service for Rapid Financial Engineering and for pretty complex Derivatives Analytics tasks.
A full access to the DEXISION Python objects from IPython Notebook is planned.
The following uses a portfolio modelled in DEXISION to implement different option and portfolio valuations. The portfolio consists of a put and a call option on the DAX index.
import urllib
from IPython.display import HTML
# DEXISION Web service URL for example portfolio
url1 = "http://analytics.dexision.com/DEXISIONeval.py?"
url2 = "user=yhilpisch&company=pythonquants&pwd=xyz"
url3 = "&portfolio=dax_put_call/portfolio"
url4 = "&strike=%s&format=%s"
dx_service = url1 + url2 + url3 + url4
dx_connect = urllib.urlopen(dx_service % (10000, 'text')).read()
HTML(dx_connect)
import xml.dom.minidom as md
dx_connect = urllib.urlopen(dx_service % (10000, 'xml')).read()
results = md.parseString(dx_connect)
portfolio = results.getElementsByTagName("portfolio")[0]
name = portfolio.getAttribute("name")
value = portfolio.getAttribute("value")
print "Value of %s is %.3f." % (name, float(value))
%%time
valuation_results = []
for strike in range(9800, 10201, 100):
dx_connect = urllib.urlopen(dx_service % (strike, 'xml')).read()
results = md.parseString(dx_connect)
options = results.getElementsByTagName("option")
for option in options:
valuation_results.append({
'name' : option.getAttribute("name"),
'strike' : strike,
'value' : float(option.getAttribute("value"))})
valuation_results
print " option | strike | value"
print 36 * "-"
for result in valuation_results:
print "%14s | %8d | %8.3f" % (result['name'], result['strike'], result['value'])
import pandas as pd
results = pd.DataFrame(valuation_results)
results
grouped = results.groupby(['name', 'strike']).sum()
grouped
grouped.loc['call_option'].plot(title='call_option')
grouped.loc['put_option'].plot(title='put_option')
This example uses the sample portfolio in DEXISION but allows for a more flexible parametrization. In addition, the main functionality is embedded in reusable Python functions.
#
# Invoking DEXISION from IPython
#
# (c) The Python Quants GmbH
# May 2014
#
from datetime import datetime
import time
from urllib2 import *
import xml.dom.minidom as minidom
Function to get data in XML format from the DEXISION Web service.
def get_data(I, M, initial_value, strike, dd, mm, yyyy):
''' Establishing connection to DEXISION Web service. '''
url1 = "http://analytics.dexision.com/DEXISIONeval.py?"
url2 = "user=yhilpisch&company=pythonquants&pwd=xyz"
url3 = "&paths=%s&steps=%s" % (I, M)
url4 = "&portfolio=dax_put_call/portfolio"
url5 = "&initial_value=%s" % initial_value
url5 = "&format=xml&strike=%s&dd=%s&mm=%s&yyyy=%s" % (strike, dd, mm, yyyy)
req = Request(url1 + url2 + url3 + url4 + url5)
try:
connection = urlopen(req)
content = connection.read()
return content
except:
return False
Function to parse data from the Web service.
def parse_data(data):
''' Parses data given back by DEXISION in XML format. '''
dom = minidom.parseString(data)
port1 = dom.getElementsByTagName("portfolio")[0]
port2 = dom.getElementsByTagName("stock")[0]
value = port1.getAttribute("value")
name = port1.getAttribute("name")
return value, name
Main valuation routine.
def valuation(initial_value=9556.02):
''' Main Routine that implements the valuation loop. '''
I = 10000 # simulation paths
M = 50 # time steps
z = 0 # option counter
for strike in range(9750, 10250, 50): # Strike Values
print 96 * "-"
for dd, mm, yyyy in ((30, 6, 2014), (30, 9, 2014)): # Exercise Dates
data = get_data(str(I), str(M), str(initial_value), str(strike),
str(dd), str(mm), str(yyyy))
if data is False:
print "Connection failed. Try again in 5 Sec."
else:
value, name = parse_data(data)
print ("Time %s |Value of %13s: %8.3f |"
+ "DAX %s - K %5d - T %s") \
% (datetime.now().replace(microsecond=0),
name, float(value), initial_value,
strike, datetime(yyyy, mm, dd).date())
z += 1
return z
And the valuation itself.
%time valuation()
The example is based on a Monte Carlo simulation algorithm.
def bsm_mcs_value(S0):
''' Dynamic Black-Scholes-Merton MCS Estimator for European Calls. '''
import numpy as np
K = 100.; T = 1.0; r = 0.05; vola = 0.2
M = 50; I = 50000
dt = T / M
rand = np.random.standard_normal((M + 1, I))
S = np.zeros((M + 1, I)); S[0] = S0
for t in range(1, M + 1):
S[t] = S[t-1] * np.exp((r - 0.5 * vola ** 2) * dt + vola * np.sqrt(dt) * rand[t])
option_value = np.sum(np.maximum(S[-1] - K, 0)) / I
return option_value
The benchmark is the sequential calculation.
import numpy as np
def seq_value(n):
option_values = []
for S in np.linspace(80, 100, n):
option_values.append(bsm_mcs_value(S))
return np.array(option_values)
n = 25
%time seq_values = seq_value(n)
seq_values.round(3)
Setting up IPython.parallel.
from IPython.parallel import Client
c = Client(profile="default")
view = c.load_balanced_view()
The parallel valuation function.
def par_value(n):
option_values = []
for s0 in np.linspace(80, 100, n):
value = view.apply_async(bsm_mcs_value, s0)
# asynchronously calculate the option values
option_values.append(value)
c.wait(option_values)
return option_values
%time par_values = par_value(n)
results = np.array(map(lambda x: x.result, par_values))
results.round(3)
from IPython.html.widgets import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from pylab import cm
%matplotlib inline
class call_option(object):
from math import log, sqrt, exp
from scipy import stats
global log, sqrt, exp, stats
def __init__(self, S0, K, T, r, sigma):
self.S0 = float(S0)
self.K = K
self.T = T
self.r = r
self.sigma = sigma
def value(self):
''' Return option value. '''
d1 = ((log(self.S0 / self.K) + (self.r + 0.5 * self.sigma ** 2) * self.T)
/ (self.sigma * sqrt(self.T)))
d2 = ((log(self.S0 / self.K) + (self.r - 0.5 * self.sigma ** 2) * self.T)
/ (self.sigma * sqrt(self.T)))
value = (self.S0 * stats.norm.cdf(d1, 0.0, 1.0)
- self.K * exp(-self.r * self.T) * stats.norm.cdf(d2, 0.0, 1.0))
return value
def vega(self):
''' Return Vega of option. '''
d1 = ((log(self.S0 / self.K)
+ (self.r + (0.5 * self.sigma ** 2)) * self.T)
/ (self.sigma * sqrt(self.T)))
vega = self.S0 * stats.norm.cdf(d1, 0.0, 1.0) * sqrt(self.T)
return vega
def vega_calculation(S0=100, T=1.0, r=0.01, sigma=0.2, n=10):
np.set_printoptions(formatter={'all' :
lambda x: '%6.2f' % x})
o = call_option(S0, 100, T, r, sigma)
strikes = np.linspace(80, 120, n)
vegas = []
for k in strikes:
o.K = k
vegas.append(o.vega())
print "Strike:", strikes.round(3)
print "Vega: ", np.array(vegas).round(3)
interact(vega_calculation, S0=(75, 125, 1),
T=(0.01, 2.0, 0.01),
r=(0.0, 0.1, 0.005),
sigma=(0.01, 0.5, 0.01),
n=(1, 20, 1))
def vega_plot_2d(S0=100, T=1.0, r=0.01, sigma=0.2):
o = call_option(S0, 100, T, r, sigma)
strikes = np.linspace(80, 120, 20)
vegas = []
for k in strikes:
o.K = k
vegas.append(o.vega())
plt.figure(figsize=(8, 5))
plt.plot(strikes, vegas)
plt.grid(True)
plt.xlabel('strike')
plt.ylabel('Vega')
interact(vega_plot_2d, S0=(75, 125, 1),
T=(0.01, 2.0, 0.01),
r=(0.0, 0.1, 0.005),
sigma=(0.01, 0.5, 0.01))
def vega_plot_3d(S0=100, r=0.01, sigma=0.2):
o = call_option(S0, 100, 1.0, r, sigma)
maturities = np.linspace(0.05, 2.0, 20)
strikes = np.linspace(80, 120, 20)
T, K = np.meshgrid(strikes, maturities)
V = np.zeros_like(K)
for t in enumerate(maturities):
for k in enumerate(strikes):
o.T = t[1]
o.K = k[1]
V[t[0], k[0]] = o.vega()
fig = plt.figure(figsize=(10, 5))
ax = fig.gca(projection='3d')
surf = ax.plot_surface(T, K, V, rstride=1, cstride=1,
cmap=cm.coolwarm, linewidth=0.5, antialiased=True)
ax.set_xlabel('strike')
ax.set_ylabel('maturity')
ax.set_zlabel('Vega of European call option')
fig.colorbar(surf, shrink=0.5, aspect=5)
interact(vega_plot_3d, S0=(75, 125, 1),
r=(0.0, 0.1, 0.005),
sigma=(0.01, 0.5, 0.01))