Wishart model

calibration_crosssectional(underlying_price, strikes, expiries, option_prices, initial_guess, put=False, weights=None, n_cores=None)

Wishart cross-sectional calibration

Recovers the Wishart model parameters from options prices at a single point in time. The calibration is performed using the Levenberg-Marquardt algorithm.

Parameters

underlying_price : float Price of the underlying asset. strikes : numpy.array One-dimensional array of option strikes. Must be of the same length as the expiries and option_prices arrays. expiries : numpy.array One-dimensional array of option expiries. The expiries are the time remaining until the expiry of the option. Must be of the same length as the strikes and option_prices arrays. option_prices : numpy.array One-dimensional array of call options prices. Must be of the same length as the expiries and strikes arrays. initial_guess : tuple Initial guess for instantaneous volatility matrix :math:\Sigma_0 and the Wishart parameters :math:\beta, :math:Q, :math:M and :math:R. put : bool, optional Whether the option is a put option. Defaults to False. weights : numpy.array, optional One-dimensional array of call options prices. Must be of the same length as the option_prices, expiries and strikes arrays.

Returns

tuple Returns the calibrated instantaneous volatility :math:V_0 and the Wishart parameters :math:\kappa, :math:\theta, :math:\nu and :math:\rho, respectively, as :obj:float.

Example

import numpy as np from fyne import wishart params = dict( vol=np.array([[0.0327, 0.0069], [0.0069, 0.0089]]), beta=0.6229, q=np.array([[0.3193, 0.2590], [0.2899, 0.2469]]), m=np.array([[-0.9858, -0.5224], [-0.1288, -0.9746]]), r=np.array([[-0.2116, -0.4428], [-0.2113, -0.5921]]), ) underlying_price = 1640. strikes = np.array([1148., 1148., 1148., 1148., ... 1312., 1312., 1312., 1312., ... 1640., 1640., 1640., 1640., ... 1968., 1968., 1968., 1968., ... 2296., 2296., 2296., 2296.]) expiries = np.array([0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5]) put = np.array([False, False, False, False, ... False, False, False, False, ... False, False, False, False, ... False, False, False, False, ... True, True, True, True]) option_prices = wishart.formula(underlying_price, strikes, expiries, ... put=put, **params) initial_guess = np.array([vol + 0.01, kappa + 1, theta + 0.01, ... nu - 0.1, rho - 0.1]) calibrated = heston.calibration_crosssectional( ... underlying_price, strikes, expiries, option_prices, initial_guess, ... put) [np.round(param, 4) for param in calibrated] [0.0457, 5.07, 0.0457, 0.48, -0.767]

Source code in src/fyne/wishart/core.py
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def calibration_crosssectional(
    underlying_price,
    strikes,
    expiries,
    option_prices,
    initial_guess,
    put=False,
    weights=None,
    n_cores=None,
):
    r"""Wishart cross-sectional calibration

    Recovers the Wishart model parameters from options prices at a single point
    in time. The calibration is performed using the Levenberg-Marquardt
    algorithm.

    Parameters
    ----------
    underlying_price : float
        Price of the underlying asset.
    strikes : numpy.array
        One-dimensional array of option strikes. Must be of the same length as
        the expiries and option_prices arrays.
    expiries : numpy.array
        One-dimensional array of option expiries. The expiries are the time
        remaining until the expiry of the option. Must be of the same length as
        the strikes and option_prices arrays.
    option_prices : numpy.array
        One-dimensional array of call options prices. Must be of the same
        length as the expiries and strikes arrays.
    initial_guess : tuple
        Initial guess for instantaneous volatility matrix :math:`\Sigma_0` and
        the Wishart parameters :math:`\beta`, :math:`Q`, :math:`M` and
        :math:`R`.
    put : bool, optional
        Whether the option is a put option. Defaults to `False`.
    weights : numpy.array, optional
        One-dimensional array of call options prices. Must be of the same
        length as the option_prices, expiries and strikes arrays.

    Returns
    -------
    tuple
        Returns the calibrated instantaneous volatility :math:`V_0` and the
        Wishart parameters :math:`\kappa`, :math:`\theta`, :math:`\nu` and
        :math:`\rho`, respectively, as :obj:`float`.

    Example
    -------

    >>> import numpy as np
    >>> from fyne import wishart
    >>> params = dict(
    >>>     vol=np.array([[0.0327, 0.0069],
    >>>                   [0.0069, 0.0089]]),
    >>>     beta=0.6229,
    >>>     q=np.array([[0.3193, 0.2590],
    >>>                 [0.2899, 0.2469]]),
    >>>     m=np.array([[-0.9858, -0.5224],
    >>>                 [-0.1288, -0.9746]]),
    >>>     r=np.array([[-0.2116, -0.4428],
    >>>                 [-0.2113, -0.5921]]),
    >>> )
    >>> underlying_price = 1640.
    >>> strikes = np.array([1148., 1148., 1148., 1148.,
    ...                     1312., 1312., 1312., 1312.,
    ...                     1640., 1640., 1640., 1640.,
    ...                     1968., 1968., 1968., 1968.,
    ...                     2296., 2296., 2296., 2296.])
    >>> expiries = np.array([0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5])
    >>> put = np.array([False, False, False, False,
    ...                 False, False, False, False,
    ...                 False, False, False, False,
    ...                 False, False, False, False,
    ...                 True, True, True, True])
    >>> option_prices = wishart.formula(underlying_price, strikes, expiries,
    ...                                 put=put, **params)
    >>> initial_guess = np.array([vol + 0.01, kappa + 1, theta + 0.01,
    ...                           nu - 0.1, rho - 0.1])
    >>> calibrated = heston.calibration_crosssectional(
    ...     underlying_price, strikes, expiries, option_prices, initial_guess,
    ...     put)
    >>> [np.round(param, 4) for param in calibrated]
    [0.0457, 5.07, 0.0457, 0.48, -0.767]

    """

    calls = common._put_call_parity_reverse(
        option_prices, underlying_price, strikes, put
    )
    cs = calls / underlying_price
    ks = np.log(strikes / underlying_price)
    ws = 1 / cs if weights is None else weights / cs

    vol0, beta0, q0, m0, r0 = initial_guess
    if vol0.shape != (2, 2):
        raise NotImplementedError(
            "Only 2-factor Wishart is currently available."
        )

    return _reduced_calib_xsect(
        cs, ks, expiries, ws, vol0, beta0, q0, m0, r0, n_cores
    )

calibration_vol(underlying_price, strikes, expiries, option_prices, vol_guess, beta, q, m, r, put=False, weights=None, n_cores=None)

Wishart volatility matrix calibration

Recovers the Wishart instantaneous volatility matrix from options prices at a single point in time. The Wishart model parameters must be provided. The calibration is performed using the Levenberg-Marquardt algorithm.

Parameters

underlying_price : float Price of the underlying asset. strikes : numpy.array One-dimensional array of option strikes. Must be of the same length as the expiries and option_prices arrays. expiries : numpy.array One-dimensional array of option expiries. The expiries are the time remaining until the expiry of the option. Must be of the same length as the strikes and option_prices arrays. option_prices : numpy.array One-dimensional array of call options prices. Must be of the same length as the expiries and strikes arrays. vol_guess : float, optional Initial guess for instantaneous volatility :math:V_0. Defaults to 0.1. beta: float Model parameter :math:\beta. q : float matrix Model parameter :math:Q. m : float matrix Model parameter :math:M. r : float matrix Model parameter :math:R. put : bool, optional Whether the option is a put option. Defaults to False. weights : numpy.array, optional One-dimensional array of call options prices. Must be of the same length as the option_prices, expiries and strikes arrays.

Returns

float Returns the calibrated instantaneous volatility :math:V_0.

Example

import numpy as np from fyne import wishart params = dict( vol=np.array([[0.0327, 0.0069], [0.0069, 0.0089]]), beta=0.6229, q=np.array([[0.3193, 0.2590], [0.2899, 0.2469]]), m=np.array([[-0.9858, -0.5224], [-0.1288, -0.9746]]), r=np.array([[-0.2116, -0.4428], [-0.2113, -0.5921]]), ) underlying_price = 1640. strikes = np.array([1148., 1148., 1148., 1148., ... 1312., 1312., 1312., 1312., ... 1640., 1640., 1640., 1640., ... 1968., 1968., 1968., 1968., ... 2296., 2296., 2296., 2296.]) expiries = np.array([0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5, ... 0.12, 0.19, 0.25, 0.5]) put = np.array([False, False, False, False, ... False, False, False, False, ... False, False, False, False, ... False, False, False, False, ... True, True, True, True]) option_prices = wishart.formula(underlying_price, strikes, expiries, ... put=put, **params) calibrated_vol = wishart.calibration_vol( ... underlying_price, strikes, expiries, option_prices, kappa, theta, ... nu, rho, put) np.round(calibrated_vol, 4) 0.0457

Source code in src/fyne/wishart/core.py
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
def calibration_vol(
    underlying_price,
    strikes,
    expiries,
    option_prices,
    vol_guess,
    beta,
    q,
    m,
    r,
    put=False,
    weights=None,
    n_cores=None,
):
    r"""Wishart volatility matrix calibration

    Recovers the Wishart instantaneous volatility matrix from options prices at
    a single point in time. The Wishart model parameters must be provided. The
    calibration is performed using the Levenberg-Marquardt algorithm.

    Parameters
    ----------
    underlying_price : float
        Price of the underlying asset.
    strikes : numpy.array
        One-dimensional array of option strikes. Must be of the same length as
        the expiries and option_prices arrays.
    expiries : numpy.array
        One-dimensional array of option expiries. The expiries are the time
        remaining until the expiry of the option. Must be of the same length as
        the strikes and option_prices arrays.
    option_prices : numpy.array
        One-dimensional array of call options prices. Must be of the same
        length as the expiries and strikes arrays.
    vol_guess : float, optional
        Initial guess for instantaneous volatility :math:`V_0`. Defaults to
        0.1.
    beta: float
        Model parameter :math:`\beta`.
    q : float matrix
        Model parameter :math:`Q`.
    m : float matrix
        Model parameter :math:`M`.
    r : float matrix
        Model parameter :math:`R`.
    put : bool, optional
        Whether the option is a put option. Defaults to `False`.
    weights : numpy.array, optional
        One-dimensional array of call options prices. Must be of the same
        length as the option_prices, expiries and strikes arrays.

    Returns
    -------
    float
        Returns the calibrated instantaneous volatility :math:`V_0`.

    Example
    -------

    >>> import numpy as np
    >>> from fyne import wishart
    >>> params = dict(
    >>>     vol=np.array([[0.0327, 0.0069],
    >>>                   [0.0069, 0.0089]]),
    >>>     beta=0.6229,
    >>>     q=np.array([[0.3193, 0.2590],
    >>>                 [0.2899, 0.2469]]),
    >>>     m=np.array([[-0.9858, -0.5224],
    >>>                 [-0.1288, -0.9746]]),
    >>>     r=np.array([[-0.2116, -0.4428],
    >>>                 [-0.2113, -0.5921]]),
    >>> )
    >>> underlying_price = 1640.
    >>> strikes = np.array([1148., 1148., 1148., 1148.,
    ...                     1312., 1312., 1312., 1312.,
    ...                     1640., 1640., 1640., 1640.,
    ...                     1968., 1968., 1968., 1968.,
    ...                     2296., 2296., 2296., 2296.])
    >>> expiries = np.array([0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5,
    ...                      0.12, 0.19, 0.25, 0.5])
    >>> put = np.array([False, False, False, False,
    ...                 False, False, False, False,
    ...                 False, False, False, False,
    ...                 False, False, False, False,
    ...                 True, True, True, True])
    >>> option_prices = wishart.formula(underlying_price, strikes, expiries,
    ...                                 put=put, **params)
    >>> calibrated_vol = wishart.calibration_vol(
    ...     underlying_price, strikes, expiries, option_prices, kappa, theta,
    ...     nu, rho, put)
    >>> np.round(calibrated_vol, 4)
    0.0457

    """

    calls = common._put_call_parity_reverse(
        option_prices, underlying_price, strikes, put
    )
    cs = calls / underlying_price
    ks = np.log(strikes / underlying_price)
    ws = 1 / cs if weights is None else weights / cs

    return _reduced_calib_vol(
        cs, ks, expiries, ws, vol_guess, beta, q, m, r, n_cores
    )

delta(underlying_price, strike, expiry, vol, beta, q, m, r, put=False)

Wishart Greek delta

Computes the Greek :math:\Delta (delta) of the option according to the Wishart model.

Parameters

underlying_price : float Price of the underlying asset. strike : float Strike of the option. expiry : float Time remaining until the expiry of the option. vol : float Instantaneous volatility. beta: float Model parameter :math:\beta. q : float matrix Model parameter :math:Q. m : float matrix Model parameter :math:M. r : float matrix Model parameter :math:R. put : bool, optional Whether the option is a put option. Defaults to False.

Returns

float Option Greek :math:\Delta (delta) according to Wishart formula.

Source code in src/fyne/wishart/core.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
def delta(underlying_price, strike, expiry, vol, beta, q, m, r, put=False):
    r"""Wishart Greek delta

    Computes the Greek :math:`\Delta` (delta) of the option according to the
    Wishart model.

    Parameters
    ----------
    underlying_price : float
        Price of the underlying asset.
    strike : float
        Strike of the option.
    expiry : float
        Time remaining until the expiry of the option.
    vol : float
        Instantaneous volatility.
    beta: float
        Model parameter :math:`\beta`.
    q : float matrix
        Model parameter :math:`Q`.
    m : float matrix
        Model parameter :math:`M`.
    r : float matrix
        Model parameter :math:`R`.
    put : bool, optional
        Whether the option is a put option. Defaults to `False`.

    Returns
    -------
    float
        Option Greek :math:`\Delta` (delta) according to Wishart formula.

    """

    k = np.log(strike / underlying_price)

    @np.vectorize
    def vec_reduced_delta(k, t):
        return _reduced_delta(k, t, vol, beta, q, m, r)

    call_delta = vec_reduced_delta(k, expiry)
    return common._put_call_parity_delta(call_delta, put)

formula(underlying_price, strike, expiry, vol, beta, q, m, r, put=False, n_cores=None)

Wishart model formula

Computes the price of the option according to the Wishart model formula.

Parameters

underlying_price : float Price of the underlying asset. strike : float Strike of the option. expiry : float Time remaining until the expiry of the option. vol : float matrix Instantaneous volatility matrix. beta: float Model parameter :math:\beta. q : float matrix Model parameter :math:Q. m : float matrix Model parameter :math:M. r : float matrix Model parameter :math:R. put : bool, optional Whether the option is a put option. Defaults to False.

Returns

float Option price according to Wishart model formula.

Source code in src/fyne/wishart/core.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def formula(
    underlying_price,
    strike,
    expiry,
    vol,
    beta,
    q,
    m,
    r,
    put=False,
    n_cores=None,
):
    r"""Wishart model formula

    Computes the price of the option according to the Wishart model formula.

    Parameters
    ----------
    underlying_price : float
        Price of the underlying asset.
    strike : float
        Strike of the option.
    expiry : float
        Time remaining until the expiry of the option.
    vol : float matrix
        Instantaneous volatility matrix.
    beta: float
        Model parameter :math:`\beta`.
    q : float matrix
        Model parameter :math:`Q`.
    m : float matrix
        Model parameter :math:`M`.
    r : float matrix
        Model parameter :math:`R`.
    put : bool, optional
        Whether the option is a put option. Defaults to `False`.

    Returns
    -------
    float
        Option price according to Wishart model formula.
    """

    if vol.shape != (2, 2):
        raise NotImplementedError(
            "Only 2-factor Wishart is currently available."
        )
    ks = np.log(strike / underlying_price)
    broadcasted = np.broadcast(ks, expiry)
    call = np.empty(broadcasted.shape)
    if n_cores is None:
        call.flat = [
            _reduced_formula(k, t, vol, beta, q, m, r)
            for (k, t) in broadcasted
        ]
    else:
        with ProcessPoolExecutor(max_workers=n_cores) as executor:
            call.flat = list(
                executor.map(
                    _reduced_formula,
                    *zip(*broadcasted),
                    *map(repeat, (vol, beta, q, m, r)),
                )
            )
    call *= underlying_price
    return common._put_call_parity(call, underlying_price, strike, put)

vega(underlying_price, strike, expiry, vol, beta, q, m, r)

Wishart Greek vega

Computes the Greek :math:\mathcal{V} (vega) of the option according to the Wishart model. This is the gradient of the option price with respect to the volatility matrix.

Parameters

underlying_price : float Price of the underlying asset. strike : float Strike of the option. expiry : float Time remaining until the expiry of the option. vol : float Instantaneous volatility. beta: float Model parameter :math:\beta. q : float matrix Model parameter :math:Q. m : float matrix Model parameter :math:M. r : float matrix Model parameter :math:R.

Returns

float Option Greek :math:\mathcal{V} (vega) according to Wishart formula.

Source code in src/fyne/wishart/core.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def vega(underlying_price, strike, expiry, vol, beta, q, m, r):
    r"""Wishart Greek vega

    Computes the Greek :math:`\mathcal{V}` (vega) of the option according to
    the Wishart model. This is the gradient of the option price with respect to
    the volatility matrix.

    Parameters
    ----------
    underlying_price : float
        Price of the underlying asset.
    strike : float
        Strike of the option.
    expiry : float
        Time remaining until the expiry of the option.
    vol : float
        Instantaneous volatility.
    beta: float
        Model parameter :math:`\beta`.
    q : float matrix
        Model parameter :math:`Q`.
    m : float matrix
        Model parameter :math:`M`.
    r : float matrix
        Model parameter :math:`R`.

    Returns
    -------
    float
        Option Greek :math:`\mathcal{V}` (vega) according to Wishart formula.

    """

    k = np.log(strike / underlying_price)

    @np.vectorize
    def vec_reduced_vega(k, t):
        return _reduced_vega(k, t, vol, beta, q, m, r)

    return vec_reduced_vega(k, expiry) * underlying_price