Conquering the Analytics Space
Dr. Yves J. Hilpisch | The Python Quants GmbH
analytics@pythonquants.com | www.pythonquants.com
PyData New York City, 22. November 2014
Black-Scholes-Merton (1973) SDE of geometric Brownian motion. The "Hello World example of Quant Finance."
$$ dS_t = rS_tdt + \sigma S_t dZ_t $$
Monte Carlo simulation: draw $I$ standard normally distributed random number $z_t^i$ and apply them to the following by Euler disctretization scheme to simulate $I$ end values of the GBM:
$$ S_{T} = S_0 \exp \left(\left( r - \frac{1}{2} \sigma^2\right) T + \sigma \sqrt{T} z_T \right) $$
Latex description of Euler discretization.
S_T = S_0 \exp (( r - 0.5 \sigma^2 ) T + \sigma \sqrt{T} z_T)
Python implementation of algorithm.
from pylab import *
S_0 = 100.; r = 0.01; T = 0.5; sigma = 0.2
z_T = standard_normal(10000)
S_T = S_0 * exp((r - 0.5 * sigma ** 2) * T + sigma * sqrt(T) * z_T)
Again, Latex for comparison:
S_T = S_0 \exp (( r - 0.5 \sigma^2 ) T + \sigma \sqrt{T} z_T)
Interactive visualization of simulation results.
%matplotlib inline
pyfig = figure()
hist(S_T, bins=40);
grid()
The Python ecosystem can be considered one of the major competitive advantages of the language.
Python integrates pretty well with almost any other language used for scientific and financial computing.
We analyze the statistical correlation between the EURO STOXX 50 stock index and the VSTOXX volatility index.
First, reading the EURO STOXX 50 & VSTOXX data.
import pandas as pd
es = pd.HDFStore('data/SX5E.h5', 'r')['SX5E']
vs = pd.HDFStore('data/V2TX.h5', 'r')['V2TX']
es['SX5E'].plot(figsize=(9, 6))
<matplotlib.axes.AxesSubplot at 0x10f9d5f10>
Generating log returns with Python and pandas.
import numpy as np
# log returns for the major indices' time series data
datv = pd.DataFrame({'SX5E' : es['SX5E'], 'V2TX': vs['V2TX']}).dropna()
rets = np.log(datv / datv.shift(1)).dropna()
ES = rets['SX5E'].values
VS = rets['V2TX'].values
Bridging to R from within IPython Notebook and pushing Python data to the R run-time.
%load_ext rpy2.ipython
The rpy2.ipython extension is already loaded. To reload it, use: %reload_ext rpy2.ipython
%Rpush ES VS
Plotting with R in IPython Notebook.
%R plot(ES, VS, pch=19, col='blue'); grid(); title("Log returns ES50 & VSTOXX")
Linear regression with R.
%R c = coef(lm(VS~ES))
<FloatVector - Python:0x115c647e8 / R:0x10bd931c8> [-0.000074, -2.752754]
%R print(summary(lm(VS~ES)))
Call: lm(formula = VS ~ ES) Residuals: Min 1Q Median 3Q Max -0.32412 -0.02188 -0.00213 0.02015 0.53675 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -7.416e-05 6.169e-04 -0.12 0.904 ES -2.753e+00 4.078e-02 -67.50 <2e-16 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 0.03905 on 4006 degrees of freedom Multiple R-squared: 0.5321, Adjusted R-squared: 0.532 F-statistic: 4556 on 1 and 4006 DF, p-value: < 2.2e-16
Regression line visualized.
%R plot(ES, VS, pch=19, col='blue'); grid(); abline(c, col='red', lwd=5)
Pulling data from R to Python and using it.
%Rpull c
plt.figure(figsize=(9, 6))
plt.plot(ES, VS, 'b.')
plt.plot(ES, c[0] + c[1] * ES, 'r', lw=3)
plt.grid(); plt.xlabel('ES'); plt.ylabel('VS')
<matplotlib.text.Text at 0x116005690>
If you want to have it nicer, interactive and embeddable anywhere – use plot.ly
import plotly.plotly as ply
ply.sign_in('yves', 'token')
Let us generate a plot with fewer data points.
pyfig = plt.figure(figsize=(9, 6)); n = 100
plt.plot(ES[:n], VS[:n], 'b.')
plt.plot(ES[:n], c[0] + c[1] * ES[:n], 'r', lw=3)
plt.grid(); plt.xlabel('ES'); plt.ylabel('VS')
<matplotlib.text.Text at 0x11623f510>
Only single line of code needed to convert matplotlib plot into interactive D3 plot.
ply.iplot_mpl(pyfig) # convert mpl plot into interactive D3
Julia is, for example, often faster for iterative function formulations. As an example, consider the Fibonacci sequence.
# quite slow in Python
def fib_rec(n):
if n < 2:
return n
else:
return fib_rec(n - 1) + fib_rec(n - 2)
%time fib_rec(35)
CPU times: user 2.87 s, sys: 29 ms, total: 2.9 s Wall time: 2.85 s
9227465
%%julia
# much faster in Julia
fib_rec(n) = n < 2 ? n : fib_rec(n - 1) + fib_rec(n - 2)
@elapsed fib_rec(35)
fib_rec (generic function with 1 method) 0.072275267
For comparison, an iterative function implementation.
# iterative version in Python
def fib_it(n):
x,y = 0, 1
for i in xrange(1, n + 1):
x, y = y, x + y
return x
%time fn = fib_it(1000000) # with 1,000,000
CPU times: user 9.6 s, sys: 32 ms, total: 9.64 s Wall time: 9.41 s
%%julia
# iterative version in Julia
function fib_it(n)
x, y = (0,1)
for i = 1:n
x, y = (y, x + y)
end
return x
end
fib_it(5) # initial call
@elapsed fib_it(10000000) # with 10,000,000
fib_it (generic function with 1 method) 5 0.005006169
For final comparison, the dynamically compiled Python version with Numba.
import numba
fib_nb = numba.jit(fib_it)
%timeit fib_nb(10000000) # with 10,000,000
100 loops, best of 3: 4.91 ms per loop
Finance algorithms are loop-heavy; Python loops are slow; Python is too slow for finance.
def counting_py(N):
s = 0
for i in xrange(N):
for j in xrange(N):
s += int(cos(log(1)))
return s
N = 2000
%time counting_py(N)
# memory efficient but slow
CPU times: user 10.7 s, sys: 782 ms, total: 11.5 s Wall time: 10.9 s
4000000
First approach: vectorization with NumPy.
%%time
arr = ones((N, N))
print int(sum(cos(log(arr))))
4000000 CPU times: user 109 ms, sys: 49.4 ms, total: 158 ms Wall time: 201 ms
arr.nbytes # much faster but NOT memory efficient
32000000
Second approach: dynamic compiling with Numba.
import numba
counting_nb = numba.jit(counting_py)
%time counting_nb(N)
# some overhead the first time
CPU times: user 177 ms, sys: 56.5 ms, total: 234 ms Wall time: 367 ms
4000000
%timeit counting_nb(N)
# even faster AND memory efficient
10 loops, best of 3: 56.7 ms per loop
Hardware-bound IO operations are standard for Python.
%time one_gb = standard_normal((12500, 10000))
one_gb.nbytes
# a giga byte worth of data
CPU times: user 5.66 s, sys: 435 ms, total: 6.1 s Wall time: 7.11 s
1000000000
%time save('one_gb', one_gb)
CPU times: user 54.9 ms, sys: 1.77 s, total: 1.82 s Wall time: 2.58 s
!ls -n one_gb*
-rw-r--r-- 1 501 20 1000000080 21 Nov 20:50 one_gb.npy
!rm one_gb*
Integrating it all and adding collaboration and scalability (http://quant-platform.com).
At the moment, the Python Quant Platform comprises the following components and features:
rpy2
and IPython Notebook DX Analytics is a Python library for advanced derivatives and risk analytics. Just recently open sourced (cf. http://dx-analytics.com, cf. http://github.com/yhilpisch/dx)
Important research milestones (I), from a rather personal perspective.
Important research milestones (II), from a rather personal perspective.
DX Analytics leverages the experience of using Python for derivatives analytics since about 10 years.
You can register for a PQP trial (incl. DX Analytics) here http://trial.quant-platform.com.
This brief section 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.
import dx
import datetime as dt
import pandas as pd
The first step is to define a model for the risk-neutral discounting.
r = dx.constant_short_rate('r', 0.01)
We then define a market environment containing the major parameter specifications needed,
me_1 = dx.market_environment('me', dt.datetime(2015, 1, 1))
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(2016, 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).
gbm_1 = dx.geometric_brownian_motion('gbm_1', me_1)
Some paths visualized.
pdf = pd.DataFrame(gbm_1.get_instrument_values(), index=gbm_1.time_grid)
%matplotlib inline
pdf.ix[:, :10].plot(legend=False)
<matplotlib.axes.AxesSubplot at 0x10ad71790>
Second risk factor with higher volatility. We overwrite the respective value in the market environment.
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
gbm_2 = dx.geometric_brownian_motion('gbm_2', me_2)
pdf = pd.DataFrame(gbm_2.get_instrument_values(), index=gbm_2.time_grid)
pdf.ix[:, :10].plot(legend=False)
<matplotlib.axes.AxesSubplot at 0x10b132450>
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.
me_opt = dx.market_environment('me_opt', me_1.pricing_date)
me_opt.add_environment(me_1)
me_opt.add_constant('maturity', dt.datetime(2016, 6, 30))
me_opt.add_constant('strike', 110.)
The first derivative is an American put option on the first risk factor gbm_1
.
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 major Greeks.
am_put.present_value()
15.019
am_put.delta()
-0.539
am_put.vega()
57.1
The second derivative is a European call option on the second risk factor gbm_2
.
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.
eur_call.present_value()
20.659128
eur_call.delta()
0.8459
eur_call.vega()
48.3196
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.
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).
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)')
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.
risk_factors = {'gbm_1': me_1, 'gbm_2' : me_2}
correlations = [['gbm_1', 'gbm_2', -0.4]]
positions = {'put' : put, 'call' : call}
val_env = dx.market_environment('general', dt.datetime(2015, 1, 1))
val_env.add_constant('frequency', 'W')
val_env.add_constant('paths', 50000)
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.
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
Now, we can get the position values for the portfolio via the get_values
method.
port.get_values()
Total pos_value 92.868033 dtype: float64
position | name | quantity | otype | risk_facts | value | currency | pos_value | |
---|---|---|---|---|---|---|---|---|
0 | put | put | 2 | American single | [gbm_1] | 15.000000 | EUR | 30.000000 |
1 | call | call | 3 | European single | [gbm_2] | 20.956011 | EUR | 62.868033 |
Via the get_statistics
methods delta and vega values are provided as well.
port.get_statistics()
Totals pos_value 92.8680 pos_delta 0.5512 pos_vega 235.4243 dtype: float64
position | name | quantity | otype | risk_facts | value | currency | pos_value | pos_delta | pos_vega | |
---|---|---|---|---|---|---|---|---|---|---|
0 | put | put | 2 | American single | [gbm_1] | 15.000 | EUR | 30.000 | -1.1780 | 92.6000 |
1 | call | call | 3 | European single | [gbm_2] | 20.956 | EUR | 62.868 | 1.7292 | 142.8243 |
Having modeled the derivatives portfolio, risk reports are only two method calls away (I).
deltas = port.get_port_risk(Greek='Delta')
dx.risk_report(deltas)
gbm_1_Delta 0.8 0.9 1.0 1.1 1.2 factor 80.00 90.0 100.00 110.00 120.00 value 51.25 42.8 35.96 30.72 26.99 gbm_2_Delta 0.8 0.9 1.0 1.1 1.2 factor 80.00 90.00 100.00 110.00 120.00 value 25.96 30.59 35.96 41.96 48.52
Having modeled the derivatives portfolio, risk reports are only two method calls away (II).
vegas = port.get_port_risk(Greek='Vega', step=0.05)
dx.risk_report(vegas)
gbm_1_Vega 0.80 0.85 0.90 0.95 1.00 1.05 1.10 1.15 1.20 factor 0.16 0.17 0.18 0.19 0.20 0.21 0.22 0.23 0.24 value 34.15 34.60 35.05 35.50 35.96 36.42 36.89 37.35 37.81 gbm_2_Vega 0.80 0.85 0.90 0.95 1.00 1.05 1.10 1.15 1.20 factor 0.40 0.43 0.45 0.48 0.50 0.53 0.55 0.58 0.60 value 31.15 32.36 33.56 34.76 35.96 37.14 38.33 39.50 40.68
Bringing back office simulation and risk management practices to front office analytics.
The following more realistic example illustrates that you can model, value and risk manage quite complex derivatives portfolios with DX Analytics. The example has the following characteristics:
from dx import *
np.random.seed(10000)
Let us start by defining a stochastic discounting object (based on CIR square-root diffusion process).
mer = market_environment(name='me', pricing_date=dt.datetime(2015, 1, 1))
mer.add_constant('initial_value', 0.005)
mer.add_constant('volatility', 0.1)
mer.add_constant('kappa', 2.0)
mer.add_constant('theta', 0.03)
mer.add_constant('paths', 1000) # 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)
Some simulated short rate paths visualized.
plt.figure(figsize=(9, 5))
plt.plot(ssr.process.time_grid, ssr.process.get_instrument_values()[:, :10]);
plt.gcf().autofmt_xdate(); plt.grid()
The example is based on a multiple, correlated risk factors (based on geomtetric Brownian motion, jump diffusion or stachastic volatility models). The basic assumptions.
# market environments
me = market_environment('gbm', dt.datetime(2015, 1, 1))
# geometric Brownian motion
me.add_constant('initial_value', 36.)
me.add_constant('volatility', 0.2)
me.add_constant('currency', 'EUR')
In addition to the input parameters of the geometric Brownian motion, we also need the following for the jump diffusions and stochastic volatility models.
# jump diffusion
me.add_constant('lambda', 0.4)
me.add_constant('mu', -0.4)
me.add_constant('delta', 0.2)
# 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)
For the portfolio valuation we also need a valuation environment.
# valuation environment
val_env = market_environment('val_env', dt.datetime(2015, 1, 1))
val_env.add_constant('paths', 1000)
val_env.add_constant('frequency', 'M')
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(2016, 12, 31))
# add valuation environment to market environments
me.add_environment(val_env)
We generate a large number of risk factors (with some random parameter values).
no = 250
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)
Correlations are also randomly chosen.
correlations = []
keys = sorted(risk_factors.keys())
for key in keys[1:]:
correlations.append([keys[0], key, np.random.choice([-0.05, 0.0, 0.05])])
correlations[:3]
[[' 1_jd', ' 2_jd', -0.050000000000000003], [' 1_jd', ' 3_sv', 0.050000000000000003], [' 1_jd', ' 4_sv', -0.050000000000000003]]
We model a certain number of derivative instruments with the following major assumptions.
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)
The derivatives_portfolio
object we compose consists of a large number derivatives positions. Each option differs with respect to the strike and the risk factor it is dependent on.
positions = {}
for i in range(4 * no):
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]
positions[i] = derivatives_position(
name='option_pos_%d' % strike,
quantity=np.random.randint(1, 10),
underlyings=[underlying],
mar_env=me_option,
otype=otype,
payoff_func=payoff_func % strike)
# number of derivivatives positions
len(positions)
1000
All is together to define the derivatives portfolio.
port_sequ = derivatives_portfolio(
name='portfolio',
positions=positions,
val_env=val_env,
risk_factors=risk_factors,
correlations=correlations,
parallel=False) # sequential calculation
The correlation matrix illstrates the market complexity.
port_sequ.val_env.get_list('correlation_matrix')
1_jd | 2_jd | 3_sv | 4_sv | 5_gbm | 6_gbm | 7_jd | 8_gbm | 9_sv | 10_sv | ... | 241_jd | 242_sv | 243_sv | 244_sv | 245_gbm | 246_jd | 247_jd | 248_sv | 249_sv | 250_jd | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1_jd | 1.00 | -0.05 | 0.05 | -0.05 | -0.05 | 0.05 | -0.05 | -0.05 | 0.05 | 0.05 | ... | -0.05 | 0.05 | 0.05 | -0.05 | 0.05 | 0 | 0.05 | 0.05 | 0 | 0 |
2_jd | -0.05 | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
3_sv | 0.05 | 0.00 | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
4_sv | -0.05 | 0.00 | 0.00 | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
5_gbm | -0.05 | 0.00 | 0.00 | 0.00 | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
6_gbm | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
7_jd | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
8_gbm | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
9_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
10_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
11_jd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
12_jd | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
13_jd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
14_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
15_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
16_jd | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
17_jd | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
18_sv | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
19_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
20_jd | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
21_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
22_gbm | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
23_gbm | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
24_sv | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
25_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
26_jd | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
27_gbm | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
28_gbm | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
29_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
30_sv | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
221_jd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
222_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
223_gbm | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
224_jd | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
225_jd | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
226_sv | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
227_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
228_jd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
229_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
230_sv | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
231_gbm | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
232_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
233_gbm | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
234_jd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
235_gbm | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
236_gbm | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
237_jd | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
238_gbm | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
239_jd | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
240_gbm | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
241_jd | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
242_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 1.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
243_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 1.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
244_sv | -0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 1.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 0 |
245_gbm | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 1.00 | 0 | 0.00 | 0.00 | 0 | 0 |
246_jd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 1 | 0.00 | 0.00 | 0 | 0 |
247_jd | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 1.00 | 0.00 | 0 | 0 |
248_sv | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 1.00 | 0 | 0 |
249_sv | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 1 | 0 |
250_jd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | ... | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0 | 0.00 | 0.00 | 0 | 1 |
250 rows × 250 columns
The call of the get_values
method to value all instruments.
%time res = port_sequ.get_statistics(fixed_seed=True)
Totals pos_value 47818.6880 pos_delta 633.1349 pos_vega 45994.4110 dtype: float64 CPU times: user 16min 58s, sys: 1min 31s, total: 18min 29s Wall time: 9min 33s
The resulting table with the results.
res.set_index('position', inplace=False)
name | quantity | otype | risk_facts | value | currency | pos_value | pos_delta | pos_vega | |
---|---|---|---|---|---|---|---|---|---|
position | |||||||||
0 | option_pos_36 | 1 | American single | [ 1_jd] | 14.017 | EUR | 14.017 | -0.6000 | 14.8000 |
1 | option_pos_37 | 3 | European single | [ 2_jd] | 7.614 | EUR | 22.842 | 1.8135 | 42.2193 |
2 | option_pos_39 | 8 | American single | [ 3_sv] | 5.553 | EUR | 44.424 | -1.2128 | 36.2088 |
3 | option_pos_36 | 3 | American single | [ 4_sv] | 9.766 | EUR | 29.298 | -1.4400 | 18.0000 |
4 | option_pos_37 | 1 | American single | [ 5_gbm] | 5.145 | EUR | 5.145 | -0.3270 | 20.5000 |
5 | option_pos_36 | 5 | European single | [ 6_gbm] | 7.660 | EUR | 38.300 | 3.1240 | 90.8225 |
6 | option_pos_38 | 8 | European single | [ 7_jd] | 7.889 | EUR | 63.112 | 5.3640 | 119.1528 |
7 | option_pos_37 | 5 | American single | [ 8_gbm] | 7.483 | EUR | 37.415 | -1.4570 | 84.5000 |
8 | option_pos_36 | 8 | European single | [ 9_sv] | 1.524 | EUR | 12.192 | 2.2024 | 11.8104 |
9 | option_pos_37 | 1 | American single | [ 10_sv] | 7.063 | EUR | 7.063 | -0.2703 | -0.9000 |
10 | option_pos_39 | 2 | European single | [ 11_jd] | 7.743 | EUR | 15.486 | 1.2608 | 33.7394 |
11 | option_pos_38 | 2 | European single | [ 12_jd] | 19.152 | EUR | 38.304 | 1.8222 | 5.5712 |
12 | option_pos_36 | 2 | European single | [ 13_jd] | 8.983 | EUR | 17.966 | 1.2834 | 32.6318 |
13 | option_pos_38 | 4 | American single | [ 14_sv] | 12.286 | EUR | 49.144 | -1.3168 | 11.6000 |
14 | option_pos_39 | 4 | American single | [ 15_sv] | 8.352 | EUR | 33.408 | -1.1064 | 7.6000 |
15 | option_pos_37 | 9 | European single | [ 16_jd] | 24.621 | EUR | 221.589 | 7.2540 | 144.0027 |
16 | option_pos_39 | 4 | American single | [ 17_jd] | 10.497 | EUR | 41.988 | -1.0556 | 77.2368 |
17 | option_pos_39 | 9 | European single | [ 18_sv] | 17.148 | EUR | 154.332 | 7.0758 | 19.3392 |
18 | option_pos_39 | 2 | American single | [ 19_sv] | 5.067 | EUR | 10.134 | -0.2970 | 9.1704 |
19 | option_pos_38 | 4 | European single | [ 20_jd] | 19.272 | EUR | 77.088 | 3.4180 | 40.5884 |
20 | option_pos_36 | 5 | European single | [ 21_sv] | 25.646 | EUR | 128.230 | 4.4240 | 3.1845 |
21 | option_pos_38 | 2 | American single | [ 22_gbm] | 8.404 | EUR | 16.808 | -0.2818 | 42.7032 |
22 | option_pos_36 | 7 | American single | [ 23_gbm] | 0.000 | EUR | 0.000 | 0.0000 | 0.0000 |
23 | option_pos_37 | 4 | European single | [ 24_sv] | 1.920 | EUR | 7.680 | 1.2920 | 1.4212 |
24 | option_pos_38 | 9 | American single | [ 25_sv] | 6.587 | EUR | 59.283 | -2.1663 | 18.0000 |
25 | option_pos_38 | 2 | European single | [ 26_jd] | 4.173 | EUR | 8.346 | 1.3576 | 13.6942 |
26 | option_pos_37 | 8 | American single | [ 27_gbm] | 7.373 | EUR | 58.984 | -6.5768 | 139.2000 |
27 | option_pos_39 | 4 | American single | [ 28_gbm] | 13.565 | EUR | 54.260 | -2.6512 | 59.6000 |
28 | option_pos_37 | 3 | European single | [ 29_sv] | 24.181 | EUR | 72.543 | 2.5482 | 8.4126 |
29 | option_pos_39 | 9 | European single | [ 30_sv] | 0.974 | EUR | 8.766 | 1.6641 | 7.1325 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
970 | option_pos_39 | 5 | American single | [221_jd] | 8.319 | EUR | 41.595 | -1.5370 | 82.5000 |
971 | option_pos_37 | 7 | American single | [222_sv] | 5.185 | EUR | 36.295 | -0.9555 | 15.4000 |
972 | option_pos_38 | 3 | European single | [223_gbm] | 12.073 | EUR | 36.219 | 2.3721 | 54.3414 |
973 | option_pos_39 | 9 | European single | [224_jd] | 2.608 | EUR | 23.472 | 3.3786 | 97.9479 |
974 | option_pos_36 | 1 | American single | [225_jd] | 8.337 | EUR | 8.337 | -0.4035 | 14.4000 |
975 | option_pos_39 | 3 | American single | [226_sv] | 16.553 | EUR | 49.659 | -0.6471 | -18.6000 |
976 | option_pos_37 | 4 | American single | [227_sv] | 5.536 | EUR | 22.144 | -0.7632 | 18.4000 |
977 | option_pos_38 | 6 | American single | [228_jd] | 6.633 | EUR | 39.798 | -1.7490 | 79.2000 |
978 | option_pos_38 | 3 | American single | [229_sv] | 5.359 | EUR | 16.077 | -0.6081 | 5.0481 |
979 | option_pos_39 | 9 | European single | [230_sv] | 7.564 | EUR | 68.076 | 5.4657 | 27.8739 |
980 | option_pos_38 | 8 | European single | [231_gbm] | 12.054 | EUR | 96.432 | 7.3864 | 84.1928 |
981 | option_pos_36 | 4 | American single | [232_sv] | 3.858 | EUR | 15.432 | -0.8972 | 14.0000 |
982 | option_pos_39 | 8 | American single | [233_gbm] | 6.920 | EUR | 55.360 | -3.4248 | 176.8000 |
983 | option_pos_38 | 7 | American single | [234_jd] | 18.878 | EUR | 132.146 | -4.9469 | 39.2000 |
984 | option_pos_37 | 9 | European single | [235_gbm] | 17.168 | EUR | 154.512 | 8.9217 | 11.8746 |
985 | option_pos_38 | 5 | American single | [236_gbm] | 18.892 | EUR | 94.460 | -2.4340 | 74.6360 |
986 | option_pos_38 | 3 | European single | [237_jd] | 9.499 | EUR | 28.497 | 2.1438 | 36.3903 |
987 | option_pos_36 | 4 | American single | [238_gbm] | 0.068 | EUR | 0.272 | -0.0504 | 15.2000 |
988 | option_pos_38 | 8 | American single | [239_jd] | 1.927 | EUR | 15.416 | -0.2880 | 50.4000 |
989 | option_pos_37 | 3 | European single | [240_gbm] | 11.243 | EUR | 33.729 | 2.1039 | 59.7411 |
990 | option_pos_36 | 7 | European single | [241_jd] | 5.854 | EUR | 40.978 | 4.9770 | 59.3271 |
991 | option_pos_37 | 6 | American single | [242_sv] | 17.708 | EUR | 106.248 | -3.1770 | -26.4000 |
992 | option_pos_38 | 4 | European single | [243_sv] | 9.336 | EUR | 37.344 | 2.5724 | 13.1680 |
993 | option_pos_39 | 9 | European single | [244_sv] | 8.799 | EUR | 79.191 | 5.7591 | 15.1164 |
994 | option_pos_37 | 7 | European single | [245_gbm] | 17.538 | EUR | 122.766 | 5.5377 | 149.1252 |
995 | option_pos_36 | 9 | American single | [246_jd] | 1.896 | EUR | 17.064 | -1.0944 | 134.1000 |
996 | option_pos_37 | 9 | European single | [247_jd] | 12.250 | EUR | 110.250 | 6.3801 | 148.0761 |
997 | option_pos_37 | 5 | American single | [248_sv] | 4.309 | EUR | 21.545 | -0.9470 | 9.5000 |
998 | option_pos_37 | 3 | European single | [249_sv] | 4.663 | EUR | 13.989 | 1.5225 | 8.1852 |
999 | option_pos_37 | 8 | American single | [250_jd] | 10.327 | EUR | 82.616 | -2.0448 | 109.2584 |
1000 rows × 9 columns
Full distribution of portfolio present values illustrated via histogram.
%time pvs = port_sequ.get_present_values()
CPU times: user 4min 22s, sys: 15.8 s, total: 4min 38s Wall time: 2min 23s
plt.figure(figsize=(9, 6)); plt.hist(pvs, bins=30);
plt.xlabel('portfolio present values');plt.ylabel('frequency'); plt.grid()
Some statistics via pandas.
pdf = pd.DataFrame(pvs, columns=['values'])
pdf.describe()
values | |
---|---|
count | 1000.000000 |
mean | 47858.798330 |
std | 3885.104955 |
min | 38795.659239 |
25% | 45115.795320 |
50% | 47705.269666 |
75% | 50224.427169 |
max | 65496.998373 |
The delta risk (sensitivities) report.
%%time
deltas = port_sequ.get_port_risk(Greek='Delta', fixed_seed=True, step=0.2,
risk_factors=risk_factors.keys()[:4])
risk_report(deltas)
39_jd_Delta 0.8 1.0 1.2 factor 37.52 46.91 56.29 value 9482.22 9508.99 9537.94 107_sv_Delta 0.8 1.0 1.2 factor 24.43 30.54 36.65 value 9513.48 9504.40 9499.51 144_sv_Delta 0.8 1.0 1.2 factor 21.36 26.7 32.04 value 9502.22 9504.4 9509.62 246_jd_Delta 0.8 1.0 1.2 factor 44.73 55.91 67.09 value 9504.39 9507.45 9515.13 CPU times: user 55.9 s, sys: 473 ms, total: 56.4 s Wall time: 54.4 s
The vega risk (sensitivities) report.
%%time
vegas = port_sequ.get_port_risk(Greek='Vega', fixed_seed=True, step=0.2,
risk_factors=risk_factors.keys()[:4])
risk_report(vegas)
39_jd_Vega 0.8 1.0 1.2 factor 0.49 0.61 0.73 value 9499.56 9507.45 9514.95 107_sv_Vega 0.8 1.0 1.2 factor 0.28 0.35 0.42 value 9506.97 9507.45 9508.34 144_sv_Vega 0.8 1.0 1.2 factor 0.50 0.62 0.75 value 9506.33 9507.45 9508.86 246_jd_Vega 0.8 1.0 1.2 factor 0.21 0.26 0.32 value 9505.67 9507.45 9510.28 CPU times: user 56.8 s, sys: 520 ms, total: 57.3 s Wall time: 55.3 s
Selected results visualized.
res[['pos_value', 'pos_delta', 'pos_vega']].hist(bins=30, figsize=(9, 6))
plt.ylabel('frequency')
<matplotlib.text.Text at 0x117bfbc90>
Sample paths for three underlyings.
paths_0 = port_sequ.underlying_objects.values()[0]
paths_0.generate_paths()
paths_1 = port_sequ.underlying_objects.values()[1]
paths_1.generate_paths()
paths_2 = port_sequ.underlying_objects.values()[2]
paths_2.generate_paths()
An the resulting plot.
pa = 5; plt.figure(figsize=(10, 6))
plt.plot(port_sequ.time_grid, paths_0.instrument_values[:, :pa], 'b');
plt.plot(port_sequ.time_grid, paths_1.instrument_values[:, :pa], 'r.-');
plt.plot(port_sequ.time_grid, paths_2.instrument_values[:, :pa], 'g-.', lw=2.5);
print 'Paths for %s (blue)' % paths_0.name
print 'Paths for %s (red)' % paths_1.name
print 'Paths for %s (green)' % paths_2.name; plt.grid()
plt.ylabel('risk factor level'); plt.gcf().autofmt_xdate()
Paths for 107_sv (blue) Paths for 144_sv (red) Paths for 39_jd (green)
By others:
By myself:
Available as ebook and from December 2015 as print version.
Forthcoming 2015 at Wiley Finance ...
from IPython.display import HTML
HTML('<iframe src="http://forpythonquants.com" \
width=100% height=650></iframe>')
My wish for Python in the future: to become THE glue language and platform for
Please contact us if you have any questions or want to get involved in our Python community events.
Python Quant Platform | http://quant-platform.com
Derivatives Analytics with Python | Derivatives Analytics @ Wiley Finance
Python for Finance | Python for Finance @ O'Reilly