<jupyter_start><jupyter_text>Vanilla closed-form with xtensor-pythonThis notebook demonstrates the usage of a python extension module built upon **xtensor-python**. The following packages are required to get it work:- xtl- xtensor- xtensor-python- pybind11- numpy- bqplot- ipyvolumeWe suggest to insall them with conda: `conda install xtensor-python xsimd bqplot ipyvolume -c quantstack -c conda-forge`so the dependencies are handled for you.<jupyter_code>import math
import numpy as np
import xtensor_closed_forms as xcf
from bqplot import (LinearScale, Lines, Axis, Figure)
import ipywidgets as widgets
import ipyvolume as ipv
from IPython.display import display<jupyter_output><empty_output><jupyter_text>1. Simple european callIn this section, we plot the price of a european call depending on the spot, and show how the volatility, maturity and ratescan influence this price curve. We can pass numpy arrays to the functions defined in `xtensor_closed_forms` even if these are not python functions. Besides, `xtensor-python` operates on numpy arrays **in place**, so the arrays are never copied.<jupyter_code>iscall = True
vol = 0.2
mat = 1.
rate = 0.04
strike = 1.
spot = np.arange(0.1, 1.9, 0.01)
# Documentation works as if it was a python function
?xcf.vanilla_discounted_payoff
price = xcf.bs_discounted_price(spot, strike, vol, mat, rate, iscall)
discounted_payoff = xcf.vanilla_discounted_payoff(spot, strike, mat, rate, iscall)
sc_x = LinearScale()
sc_y = LinearScale(max=1.)
call_graph = Lines(x=spot, y=price, scales={'x': sc_x, 'y': sc_y}, labels=['Price'], display_legend=True)
payoff_graph = Lines(x=spot, y=discounted_payoff, scales={'x': sc_x, 'y': sc_y}, labels=['Payoff'], colors=['red'],
                    display_legend=True)
ax_x = Axis(scale=sc_x, label="spot")
ax_y = Axis(scale=sc_y, orientation='vertical', label="price")

vol_slider = widgets.FloatSlider(value=vol, min=0, max=1, step=0.05, description='volatility')
def handle_vol_change(change):
    global vol
    vol = change.new
    call_graph.y = xcf.bs_discounted_price(spot, strike, vol, mat, rate, iscall)
vol_slider.observe(handle_vol_change, names='value')

rate_slider = widgets.FloatSlider(value=rate, min=0, max=0.1, step=0.01, description='rate')
def handle_rate_change(change):
    global rate
    rate = change.new
    call_graph.y = xcf.bs_discounted_price(spot, strike, vol, mat, rate, iscall)
    payoff_graph.y = xcf.vanilla_discounted_payoff(spot, strike, mat, rate, iscall)
rate_slider.observe(handle_rate_change, names='value')

mat_slider = widgets.FloatSlider(value=mat, min=0.5, max=10., step=0.5, description='maturity')
def handle_mat_change(change):
    global mat
    mat = change.new
    call_graph.y = xcf.bs_discounted_price(spot, strike, vol, mat, rate, iscall)
    payoff_graph.y = xcf.vanilla_discounted_payoff(spot, strike, mat, rate, iscall)
mat_slider.observe(handle_mat_change, names='value')

figure = Figure(marks=[call_graph, payoff_graph], axes=[ax_x, ax_y], title='European Call',
               legend_location='top-left')

r = widgets.VBox([figure, vol_slider, rate_slider, mat_slider])
display(r)<jupyter_output><empty_output><jupyter_text>2. Surface plot for many callsIn this section, we demonstrate the braodcasting feature available in `xtensor-python`. To do so, we compute the price matrix of european calls for different spots and volatilities.<jupyter_code>#This avoids having the 3D plot updated when changing the sliders of the 2D plot (and vice-versa)
iscall_2d = True
mat_2d = 1.
rate_2d = 0.04
strike_2d = 1.
spot_2d = np.arange(0.1, 1.5, 0.01)
vol_lin = np.arange(0.05, 0.35, 0.01)
vol_2d = vol_lin[:, np.newaxis]
price_2d = xcf.bs_discounted_price(spot_2d, strike_2d, vol_2d, mat_2d, rate_2d, iscall_2d)
fig = ipv.figure()
ipv.pylab.ylim(0, 0.6)
ipv.pylab.zlim(0, 0.4)
ipv.pylab.xlabel('spot')
ipv.pylab.ylabel('price')
ipv.pylab.zlabel('volatility')
x, y = np.meshgrid(spot_2d, vol_2d)
ipv.plot_mesh(x, price_2d, y)

rate_slider_2d = widgets.FloatSlider(value=rate, min=0, max=0.1, step=0.01, description='rate')
def handle_rate_change_2d(change):
    global rate_2d
    global price_2d
    rate_2d = change.new
    price_2d = xcf.bs_discounted_price(spot_2d, strike_2d, vol_2d, mat_2d, rate_2d, iscall_2d)
    mesh = ipv.plot_mesh(x, price_2d, y)
    fig.meshes = [mesh]
rate_slider_2d.observe(handle_rate_change_2d, names='value')

mat_slider_2d = mat_slider = widgets.FloatSlider(value=mat, min=0.5, max=10., step=0.5, description='maturity')
def handle_mat_change_2d(change):
    global mat_2d
    global price_2d
    mat_2d = change.new
    price_2d = xcf.bs_discounted_price(spot_2d, strike_2d, vol_2d, mat_2d, rate_2d, iscall_2d)
    mesh = ipv.plot_mesh(x, price_2d, y)
    fig.meshes = [mesh]
mat_slider_2d.observe(handle_mat_change_2d, names='value')

r_2d = widgets.VBox([fig, rate_slider_2d, mat_slider_2d])
r_2d<jupyter_output><empty_output><jupyter_text>3. Performance<jupyter_code>import timeit
s = """\
import numpy as np
import xtensor_closed_forms as xcf
x = np.random.rand(500, 100)
y = np.random.rand(500, 100)
"""
nb = 1000<jupyter_output><empty_output><jupyter_text>**numpy**<jupyter_code>timeit.timeit(stmt="res = np.sqrt(x*x + y*y)", setup=s, number=nb)<jupyter_output><empty_output><jupyter_text>**pyvectorize**<jupyter_code>timeit.timeit(stmt="res = xcf.distance_vectorized(x, y)", setup=s, number=nb)<jupyter_output><empty_output><jupyter_text>**pyarray**<jupyter_code>timeit.timeit(stmt="res = xcf.distance_array(x, y)", setup=s, number=nb)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12265512265512266, 'fraction_numerical': 0.025974025974025976, 'mean_word_length': 5.913965087281795, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '259622', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2151, 'n_tokens_neox': 2099, 'n_words': 482, 'path': 'closed_form/notebooks/vanilla.ipynb', 'repo_name': 'JohanMabille/xtensor-finance', 'size': '5544'}