Coverage for rivapy/pricing/pricing_request.py: 39%
293 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-05 14:27 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-05 14:27 +0000
1# -*- coding: utf-8 -*-
4from datetime import date, datetime
5from typing import List as _List, Union as _Union
6from rivapy.tools.interfaces import FactoryObject
7from rivapy.tools.datetools import _date_to_datetime as datetime_to_date, _datetime_to_date_list as datetime_to_date_list
10class PricingRequestBase(FactoryObject):
12 _keys = ['theo_val', 'paths_udl', 'cf_expected', 'cf_paths']
14 def __init__(self, **kwargs):
15 #validate the given keys
16 for key in kwargs.keys():
17 if key not in PricingRequestBase._keys:
18 raise ValueError("Unknown key '{}'".format(key))
19 #set the attributes
20 setattr(self, key, kwargs[key])
22 def _to_dict(self) -> dict:
23 return self.__dict__
25class GreenPPAPricingRequest(PricingRequestBase):
26 def __init__(self, theo_val: bool, cf_paths: bool=False, cf_expected: bool=False):
27 """PricingRequest for Green PPA pricing.
29 Args:
30 price (bool): If True, the :term:`Theoretical Value` is calculated.
31 cf_expected (bool, optional): If True, the paths of the simulated :term:`Cash flow` is returned. Defaults to False.
32 """
33 super().__init__(theo_val=theo_val, cf_expected=cf_expected, cf_paths=cf_paths)
36class PricingRequest:
37 # def __init__(self, calc_delta_gamma: bool = False, calc_cross_gamma: bool = True, calc_clean_price: bool = False,
38 # calc_rho: bool = False, rho_scale: float = 0.0001, calc_vega: bool = False, vega_scale: float = 0.01,
39 # calc_cross_volga: bool = False, calc_vanna: bool = False, calc_theta: bool = False,
40 # theta_scale: float = 1.0, calc_spline: bool = False, calc_grid_sizes: bool = False,
41 # calc_implied_volatility: bool = False, management_delta_limit: float = 0.01,
42 # calc_pricing_data: bool = False, calc_expected_cashflows: bool = False,
43 # calc_simulation_data: bool = False, calc_additional_information: bool = False,
44 # calc_z_spread: bool = False, calc_yield_to_maturity: bool = False, calc_convexity: bool = False,
45 # max_expected_cashflow_date: _Union[date, datetime] = None,
46 # cashflow_times: _List[_Union[date, datetime]] = None, calc_macaulay_duration: bool = False):
47 # """
48 # Defines the set of information, e.g. sensitivities, cashflow information, etc., to be calculated together with
49 # the instrument's price in the context of pricing. For some sensitivities the shift parameter for calculating
50 # the difference quotient (rather than the sensitivity in closed formula) is also stored in the pricing request
51 # object.
52 #
53 # Args: TODO: Read carefully and double-check if these guessed descriptions are valid!
54 # calc_delta_gamma (bool, optional): Flag determining if the change of the instrument's price associated with
55 # small changes of the underlying's price shall be calculated to first (and
56 # second) order within the pricing routine. Defaults to False.
57 # TODO: also second order? delta_scale=?
58 # calc_cross_gamma (bool, optional): Flag determining if the change of the instrument's price associated with
59 # small changes of two underlyings' prices (both at fist order) shall be
60 # calculated within the pricing routine. Defaults to True.
61 # TODO: why defaults to True?
62 # calc_clean_price (bool, optional): Flag determining if the instrument's clean price shall be calculated
63 # additional to its dirty price within the pricing routine.
64 # Defaults to False.
65 # calc_rho (bool, optional): Flag determining if the change of the instrument's price associated with small
66 # changes of the zero rate curve shall be calculated to first order within the
67 # pricing routine. Defaults to False.
68 # rho_scale (float, optional): Size of zero rate shift in the calculation of the change of the instrument's
69 # price associated with zero rate curve shifts as difference quotient.
70 # Defaults to 0.0001 (= 1 basis point).
71 # calc_vega (bool, optional): Flag determining if the change of the instrument's price associated with small
72 # changes of the implied volatility surface shall be calculated to first order
73 # within the pricing routine. Defaults to False.
74 # vega_scale (float, optional): Size of implied volatility shift in the calculation of the change of the
75 # instrument's price associated with implied volatility surface shifts as
76 # difference quotient. Defaults to 0.01.
77 # calc_cross_volga (bool, optional): Flag determining if the change of the instrument's price associated with
78 # small changes of two implied volatility surfaces (both at first order)
79 # shall be calculated within the pricing routine. Defaults to True.
80 # TODO: why defaults to True?
81 # calc_vanna (bool, optional): Flag determining if the change of the instrument's price associated with small
82 # changes of the underlying's price and the implied volatility surface (both at
83 # first order) shall be calculated within the pricing routine. Defaults to False.
84 # TODO: why defaults to False in contrast to cross Gamma/Volga?
85 # calc_theta (bool, optional): Flag determining if the change of the instrument's price associated with small
86 # changes of the instrument's maturity shall be calculated to first order within
87 # the pricing routine. Defaults to False.
88 # theta_scale (float, optional): Size of maturity shift in the calculation of the change of the instrument's
89 # price associated with maturity shifts as difference quotient. Defaults to 1.0
90 # calc_spline (bool, optional):
91 # calc_grid_sizes (bool, optional):
92 # calc_implied_volatility (bool, optional):
93 # management_delta_limit (float, optional):
94 # calc_pricing_data (bool, optional):
95 # calc_expected_cashflows (bool, optional):
96 # calc_simulation_data (bool, optional):
97 # calc_additional_information (bool, optional):
98 # calc_z_spread (bool, optional): Flag determining if the instrument's z-spread shall be calculated within the
99 # pricing routine. Defaults to False.
100 # calc_yield_to_maturity (bool, optional): Flag determining if the instrument's yield-to-maturity shall be
101 # calculated within the pricing routine. Defaults to False.
102 # calc_convexity (bool, optional): Flag determining if the change of the instrument's price associated with
103 # small changes of the zero rate curve shall be calculated to second order
104 # within the pricing routine. Defaults to False.
105 # max_expected_cashflow_date (_Union[date, datetime], optional):
106 # cashflow_times (_List[_Union[date, datetime]], optional):
107 # calc_macaulay_duration (bool, optional): Flag determining if the instrument's Macaulay duration shall be
108 # calculated within the pricing routine. Defaults to False.
109 # """
110 def __init__(self, calc_delta_gamma: bool = None, calc_cross_gamma: bool = None, calc_clean_price: bool = None,
111 calc_rho: bool = None, rho_scale: float = None, calc_vega: bool = None, vega_scale: float = None,
112 calc_cross_volga: bool = None, calc_vanna: bool = None, calc_theta: bool = None,
113 theta_scale: float = None, calc_spline: bool = None, calc_grid_sizes: bool = None,
114 calc_implied_volatility: bool = None, management_delta_limit: float = None,
115 calc_pricing_data: bool = None, calc_expected_cashflows: bool = None,
116 calc_simulation_data: bool = None, calc_additional_information: bool = None,
117 calc_z_spread: bool = None, calc_yield_to_maturity: bool = None, calc_convexity: bool = None,
118 max_expected_cashflow_date: _Union[date, datetime] = None,
119 cashflow_times: _List[_Union[date, datetime]] = None, calc_macaulay_duration: bool = None):
120 """
121 Defines the set of information, e.g. sensitivities, cashflow information, etc., to be calculated together with
122 the instrument's price in the context of pricing. For some sensitivities the shift parameter for calculating
123 the difference quotient (rather than the sensitivity in closed formula) is also stored in the pricing request
124 object.
126 Args: TODO: Read carefully and double-check if these guessed descriptions are valid!
127 calc_delta_gamma (bool, optional): Flag determining if the change of the instrument's price associated with
128 small changes of the underlying's price shall be calculated to first (and
129 second) order within the pricing routine. Defaults to None.
130 TODO: also second order? delta_scale=?
131 calc_cross_gamma (bool, optional): Flag determining if the change of the instrument's price associated with
132 small changes of two underlyings' prices (both at fist order) shall be
133 calculated within the pricing routine. Defaults to None.
134 calc_clean_price (bool, optional): Flag determining if the instrument's clean price shall be calculated
135 additional to its dirty price within the pricing routine.
136 Defaults to None.
137 calc_rho (bool, optional): Flag determining if the change of the instrument's price associated with small
138 changes of the zero rate curve shall be calculated to first order within the
139 pricing routine. Defaults to None.
140 rho_scale (float, optional): Size of zero rate shift in the calculation of the change of the instrument's
141 price associated with zero rate curve shifts as difference quotient.
142 Defaults to None.
143 calc_vega (bool, optional): Flag determining if the change of the instrument's price associated with small
144 changes of the implied volatility surface shall be calculated to first order
145 within the pricing routine. Defaults to None.
146 vega_scale (float, optional): Size of implied volatility shift in the calculation of the change of the
147 instrument's price associated with implied volatility surface shifts as
148 difference quotient. Defaults to None.
149 calc_cross_volga (bool, optional): Flag determining if the change of the instrument's price associated with
150 small changes of two implied volatility surfaces (both at first order)
151 shall be calculated within the pricing routine. Defaults to None.
152 calc_vanna (bool, optional): Flag determining if the change of the instrument's price associated with small
153 changes of the underlying's price and the implied volatility surface (both at
154 first order) shall be calculated within the pricing routine. Defaults to None.
155 calc_theta (bool, optional): Flag determining if the change of the instrument's price associated with small
156 changes of the instrument's maturity shall be calculated to first order within
157 the pricing routine. Defaults to None.
158 theta_scale (float, optional): Size of maturity shift in the calculation of the change of the instrument's
159 price associated with maturity shifts as difference quotient.
160 Defaults to None
161 calc_spline (bool, optional):
162 calc_grid_sizes (bool, optional):
163 calc_implied_volatility (bool, optional):
164 management_delta_limit (float, optional):
165 calc_pricing_data (bool, optional):
166 calc_expected_cashflows (bool, optional):
167 calc_simulation_data (bool, optional):
168 calc_additional_information (bool, optional):
169 calc_z_spread (bool, optional): Flag determining if the instrument's z-spread shall be calculated within the
170 pricing routine. Defaults to None.
171 calc_yield_to_maturity (bool, optional): Flag determining if the instrument's yield-to-maturity shall be
172 calculated within the pricing routine. Defaults to None.
173 calc_convexity (bool, optional): Flag determining if the change of the instrument's price associated with
174 small changes of the zero rate curve shall be calculated to second order
175 within the pricing routine. Defaults to None.
176 max_expected_cashflow_date (_Union[date, datetime], optional):
177 cashflow_times (_List[_Union[date, datetime]], optional):
178 calc_macaulay_duration (bool, optional): Flag determining if the instrument's Macaulay duration shall be
179 calculated within the pricing routine. Defaults to None.
180 """
181 self._calc_delta_gamma = calc_delta_gamma
182 self._calc_cross_gamma = calc_cross_gamma
183 self._calc_clean_price = calc_clean_price
184 self._calc_rho = calc_rho
185 self._rho_scale = rho_scale
186 self._calc_vega = calc_vega
187 self._vega_scale = vega_scale
188 self._calc_cross_volga = calc_cross_volga
189 self._calc_vanna = calc_vanna
190 self._calc_theta = calc_theta
191 self._theta_scale = theta_scale
192 self._calc_spline = calc_spline
193 self._calc_grid_sizes = calc_grid_sizes
194 self._calc_implied_volatility = calc_implied_volatility
195 self._management_delta_limit = management_delta_limit
196 self._calc_pricing_data = calc_pricing_data
197 self._calc_expected_cashflows = calc_expected_cashflows
198 self._calc_simulation_data = calc_simulation_data
199 self._calc_additional_information = calc_additional_information
200 self._calc_z_spread = calc_z_spread
201 self._calc_yield_to_maturity = calc_yield_to_maturity
202 self._calc_convexity = calc_convexity
203 self._max_expected_cashflow_date = max_expected_cashflow_date
204 self._cashflow_times = cashflow_times
205 self._calc_macaulay_duration = calc_macaulay_duration
207 @property
208 def _calc_delta_gamma(self):
209 return self.__calc_delta_gamma
211 @_calc_delta_gamma.setter
212 def _calc_delta_gamma(self, calc_delta_gamma: bool):
213 if calc_delta_gamma is not None:
214 if isinstance(calc_delta_gamma, bool):
215 self.__calc_delta_gamma = calc_delta_gamma
216 else:
217 raise TypeError("'" + str(calc_delta_gamma) + "' must be of type bool!")
219 @property
220 def _calc_cross_gamma(self):
221 return self.__calc_cross_gamma
223 @_calc_cross_gamma.setter
224 def _calc_cross_gamma(self, calc_cross_gamma: bool):
225 if calc_cross_gamma is not None:
226 if isinstance(calc_cross_gamma, bool):
227 self.__calc_cross_gamma = calc_cross_gamma
228 if self._calc_cross_gamma:
229 self.calc_delta_gamma = True
230 else:
231 raise TypeError("'" + str(calc_cross_gamma) + "' must be of type bool!")
233 @property
234 def _calc_clean_price(self):
235 return self.__calc_clean_price
237 @_calc_clean_price.setter
238 def _calc_clean_price(self, calc_clean_price: bool):
239 if calc_clean_price is not None:
240 if isinstance(calc_clean_price, bool):
241 self.__calc_clean_price = calc_clean_price
242 else:
243 raise TypeError("'" + str(calc_clean_price) + "' must be of type bool!")
245 @property
246 def _calc_rho(self):
247 return self.__calc_rho
249 @_calc_rho.setter
250 def _calc_rho(self, calc_rho: bool):
251 if calc_rho is not None:
252 if isinstance(calc_rho, bool):
253 self.__calc_rho = calc_rho
254 if self._calc_rho & ~hasattr(self, 'rho_scale'):
255 self.rho_scale = 0.0001
256 else:
257 raise TypeError("'" + str(calc_rho) + "' must be of type bool!")
259 @property
260 def _rho_scale(self):
261 return self.__rho_scale
263 @_rho_scale.setter
264 def _rho_scale(self, rho_scale: float):
265 if rho_scale is not None:
266 if isinstance(rho_scale, float):
267 self.__rho_scale = rho_scale
268 self.calc_rho = True
269 else:
270 raise TypeError("'" + str(rho_scale) + "' must be of type float!")
272 @property
273 def _calc_vega(self):
274 return self.__calc_vega
276 @_calc_vega.setter
277 def _calc_vega(self, calc_vega: bool):
278 if calc_vega is not None:
279 if isinstance(calc_vega, bool):
280 self.__calc_vega = calc_vega
281 if self._calc_vega & ~hasattr(self, 'vega_scale'):
282 self.vega_scale = 0.01
283 else:
284 raise TypeError("'" + str(calc_vega) + "' must be of type bool!")
286 @property
287 def _vega_scale(self):
288 return self.__vega_scale
290 @_vega_scale.setter
291 def _vega_scale(self, vega_scale: float):
292 if vega_scale is not None:
293 if isinstance(vega_scale, float):
294 self.__vega_scale = vega_scale
295 self.calc_vega = True
296 else:
297 raise TypeError("'" + str(vega_scale) + "' must be of type float!")
299 @property
300 def _calc_cross_volga(self):
301 return self.__calc_cross_volga
303 @_calc_cross_volga.setter
304 def _calc_cross_volga(self, calc_cross_volga: bool):
305 if calc_cross_volga is not None:
306 if isinstance(calc_cross_volga, bool):
307 self.__calc_cross_volga = calc_cross_volga
308 if self._calc_cross_volga:
309 self.calc_vega = True
310 if not hasattr(self, 'vega_scale'):
311 self.vega_scale = 0.01
312 else:
313 raise TypeError("'" + str(calc_cross_volga) + "' must be of type bool!")
315 @property
316 def _calc_vanna(self):
317 return self.__calc_vanna
319 @_calc_vanna.setter
320 def _calc_vanna(self, calc_vanna: bool):
321 if calc_vanna is not None:
322 if isinstance(calc_vanna, bool):
323 self.__calc_vanna = calc_vanna
324 if self._calc_vanna:
325 self.calc_vega = True
326 if not hasattr(self, 'vega_scale'):
327 self.vega_scale = 0.01
328 else:
329 raise TypeError("'" + str(calc_vanna) + "' must be of type bool!")
331 @property
332 def _calc_theta(self):
333 return self.__calc_theta
335 @_calc_theta.setter
336 def _calc_theta(self, calc_theta: bool):
337 if calc_theta is not None:
338 if isinstance(calc_theta, bool):
339 self.__calc_theta = calc_theta
340 if self._calc_theta & ~hasattr(self, 'theta_scale'):
341 self.theta_scale = 1.0
342 else:
343 raise TypeError("'" + str(calc_theta) + "' must be of type bool!")
345 @property
346 def _theta_scale(self):
347 return self.__theta_scale
349 @_theta_scale.setter
350 def _theta_scale(self, theta_scale: float):
351 if theta_scale is not None:
352 if isinstance(theta_scale, float):
353 self.__theta_scale = theta_scale
354 self.calc_theta = True
355 else:
356 raise TypeError("'" + str(theta_scale) + "' must be of type float!")
358 @property
359 def _calc_spline(self):
360 return self.__calc_spline
362 @_calc_spline.setter
363 def _calc_spline(self, calc_spline: bool):
364 if calc_spline is not None:
365 if isinstance(calc_spline, bool):
366 self.__calc_spline = calc_spline
367 else:
368 raise TypeError("'" + str(calc_spline) + "' must be of type bool!")
370 @property
371 def _calc_grid_sizes(self):
372 return self.__calc_grid_sizes
374 @_calc_grid_sizes.setter
375 def _calc_grid_sizes(self, calc_grid_sizes: bool):
376 if calc_grid_sizes is not None:
377 if isinstance(calc_grid_sizes, bool):
378 self.__calc_grid_sizes = calc_grid_sizes
379 else:
380 raise TypeError("'" + str(calc_grid_sizes) + "' must be of type bool!")
382 @property
383 def _calc_implied_volatility(self):
384 return self.__calc_implied_volatility
386 @_calc_implied_volatility.setter
387 def _calc_implied_volatility(self, calc_implied_volatility: bool):
388 if calc_implied_volatility is not None:
389 if isinstance(calc_implied_volatility, bool):
390 self.__calc_implied_volatility = calc_implied_volatility
391 else:
392 raise TypeError("'" + str(calc_implied_volatility) + "' must be of type bool!")
394 @property
395 def _management_delta_limit(self):
396 return self.__management_delta_limit
398 @_management_delta_limit.setter
399 def _management_delta_limit(self, management_delta_limit: float):
400 self.__management_delta_limit = management_delta_limit
402 @property
403 def _calc_pricing_data(self):
404 return self.__calc_pricing_data
406 @_calc_pricing_data.setter
407 def _calc_pricing_data(self, calc_pricing_data: bool):
408 if calc_pricing_data is not None:
409 if isinstance(calc_pricing_data, float):
410 self.__calc_pricing_data = calc_pricing_data
411 else:
412 raise TypeError("'" + str(calc_pricing_data) + "' must be of type float!")
414 @property
415 def _calc_expected_cashflows(self):
416 return self.__calc_expected_cashflows
418 @_calc_expected_cashflows.setter
419 def _calc_expected_cashflows(self, calc_expected_cashflows: bool):
420 if calc_expected_cashflows is not None:
421 if isinstance(calc_expected_cashflows, bool):
422 self.__calc_expected_cashflows = calc_expected_cashflows
423 else:
424 raise TypeError("'" + str(calc_expected_cashflows) + "' must be of type bool!")
426 @property
427 def _calc_simulation_data(self):
428 return self.__calc_simulation_data
430 @_calc_simulation_data.setter
431 def _calc_simulation_data(self, calc_simulation_data: bool):
432 if calc_simulation_data is not None:
433 if isinstance(calc_simulation_data, bool):
434 self.__calc_simulation_data = calc_simulation_data
435 else:
436 raise TypeError("'" + str(calc_simulation_data) + "' must be of type bool!")
438 @property
439 def _calc_additional_information(self):
440 return self.__calc_additional_information
442 @_calc_additional_information.setter
443 def _calc_additional_information(self, calc_additional_information: bool):
444 if calc_additional_information is not None:
445 if isinstance(calc_additional_information, bool):
446 self.__calc_additional_information = calc_additional_information
447 else:
448 raise TypeError("'" + str(calc_additional_information) + "' must be of type bool!")
450 @property
451 def _calc_z_spread(self):
452 return self.__calc_z_spread
454 @_calc_z_spread.setter
455 def _calc_z_spread(self, calc_z_spread: bool):
456 if calc_z_spread is not None:
457 if isinstance(calc_z_spread, bool):
458 self.__calc_z_spread = calc_z_spread
459 else:
460 raise TypeError("'" + str(calc_z_spread) + "' must be of type bool!")
462 @property
463 def _calc_yield_to_maturity(self):
464 return self.__calc_yield_to_maturity
466 @_calc_yield_to_maturity.setter
467 def _calc_yield_to_maturity(self, calc_yield_to_maturity: bool):
468 if calc_yield_to_maturity is not None:
469 if isinstance(calc_yield_to_maturity, bool):
470 self.__calc_yield_to_maturity = calc_yield_to_maturity
471 else:
472 raise TypeError("'" + str(calc_yield_to_maturity) + "' must be of type bool!")
474 @property
475 def _calc_convexity(self):
476 return self.__calc_convexity
478 @_calc_convexity.setter
479 def _calc_convexity(self, calc_convexity: bool):
480 if calc_convexity is not None:
481 if isinstance(calc_convexity, bool):
482 self.__calc_convexity = calc_convexity
483 if self._calc_convexity:
484 self.calc_rho = True
485 if not hasattr(self, 'rho_scale'):
486 self.rho_scale = 0.0001
487 else:
488 raise TypeError("'" + str(calc_convexity) + "' must be of type bool!")
490 @property
491 def _max_expected_cashflow_date(self):
492 return self.__max_expected_cashflow_date
494 @_max_expected_cashflow_date.setter
495 def _max_expected_cashflow_date(self, max_expected_cashflow_date: _Union[date, datetime]):
496 if max_expected_cashflow_date is not None:
497 if isinstance(max_expected_cashflow_date, datetime) | isinstance(max_expected_cashflow_date, date):
498 self.__max_expected_cashflow_date = datetime_to_date(max_expected_cashflow_date)
499 else:
500 raise TypeError("'" + str(max_expected_cashflow_date) + "' must be of type datetime or date!")
502 @property
503 def _cashflow_times(self):
504 return self.__cashflow_times
506 @_cashflow_times.setter
507 def _cashflow_times(self, cashflow_times: _List[_Union[date, datetime]]):
508 if cashflow_times is not None:
509 if isinstance(cashflow_times, list) & (
510 isinstance(cashflow_times[0], datetime) | isinstance(cashflow_times[0], date)
511 ):
512 self.__cashflow_times = datetime_to_date_list(cashflow_times)
513 else:
514 raise TypeError("'" + str(cashflow_times) + "' must be of type list of datetime or date!")
516 @property
517 def _calc_macaulay_duration(self):
518 return self.__calc_macaulay_duration
520 @_calc_macaulay_duration.setter
521 def _calc_macaulay_duration(self, calc_macaulay_duration: bool):
522 if calc_macaulay_duration is not None:
523 if isinstance(calc_macaulay_duration, bool):
524 self.__calc_macaulay_duration = calc_macaulay_duration
525 else:
526 raise TypeError("'" + str(calc_macaulay_duration) + "' must be of type bool!")
529class BondPricingRequest(PricingRequest):
530 def __init__(self, calc_clean_price: bool = False, calc_rho: bool = False, rho_scale: float = None,
531 calc_theta: bool = False, theta_scale: float = None, calc_yield_to_maturity: bool = False,
532 calc_convexity: bool = False, calc_macaulay_duration: bool = False): # TODO: clarify why no z-spread
533 """
534 Configuration of set of information to be calculated together with the bond's dirty price. In restricts the
535 general PricingRequest to the sub-set relevant for the pricing of bonds.
536 """
537 PricingRequest.__init__(self, calc_clean_price=calc_clean_price, calc_rho=calc_rho, rho_scale=rho_scale,
538 calc_theta=calc_theta, theta_scale=theta_scale,
539 calc_yield_to_maturity=calc_yield_to_maturity, calc_convexity=calc_convexity,
540 calc_macaulay_duration=calc_macaulay_duration)
543if __name__ == '__main__':
544 bond_pricing_request = BondPricingRequest()