Skip to content

Conversation

@paolodelia99
Copy link
Contributor

Added BlackVolatilitySurfaceDelta class from ORE, a Black volatility surface parameterized by market deltas, mainly used in Building FX/equity volatility surfaces from market delta quotes.

QL changes @lballabio:

  • BlackVolatilitySurfaceDelta class
  • time extrapolation logic imported from the ORE's QL fork
  • added the possibility to a have a flat extrapolation in the strike space in the InterpolatedSmileSection class as an additional constructor parameter, required from the BlackVolatilitySurfaceDelta class and from ORE's implementation of InterpolatedSmileSection class
  • strikes sanity check added in the InterepolatedSmileSection class (logic implemented in checkStrikes() private method), thought you guys might need it since it was underlined in the comments

ORE Changes @pcaspers:

  • used the QL's InterpolatedSmileSection class to retrive the SmileSection from the blackVolSmile method in the BlackVolatilitySurfaceDelta class instead of the QLE InterpolatedSmileSection since they provide the same functionalities, (QL's InterpolatedSmileSection is actually more complete than the QLE ones, but the latter is derived form FxSmileSection not present in QL) thus there no need to introduce another redundant class.

@coveralls
Copy link

coveralls commented Nov 6, 2025

Coverage Status

coverage: 74.325% (+0.03%) from 74.295%
when pulling 8e6afe6 on paolodelia99:feature/fx-options-utils
into 33e452e on lballabio:master.

Copy link
Owner

@lballabio lballabio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! A few comments, some of them for @pcaspers.


namespace QuantLib {

namespace {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An anonymous namespace in a header file doesn't make a lot of sense—namespace detail is better.



//! Extrapolate black variance using flat vol extrapolation in time direction
Real timeExtrapolatationBlackVarianceFlat(const Time t, const std::vector<double>& times,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"extrapolatation" (here and everywhere)

Copyright (C) 2019 Quaternion Risk Management Ltd
Copyright (C) 2022 Skandinaviska Enskilda Banken AB (publ)
Copyright (C) 2025 Paolo D'Elia
All rights reserved.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"All rights reserved" is in contradiction with the terms of the license below. If it's in the ORE code (it looks like it), we need to ask for its removal. @pcaspers, any idea why it's there?

Comment on lines +92 to +103
DeltaVolQuote::DeltaType dt = DeltaVolQuote::DeltaType::Spot,
DeltaVolQuote::AtmType at = DeltaVolQuote::AtmType::AtmDeltaNeutral,
ext::optional<DeltaVolQuote::DeltaType> atmDeltaType = ext::nullopt,
const Period& switchTenor = 0 * Days,
DeltaVolQuote::DeltaType ltdt = DeltaVolQuote::DeltaType::Fwd,
DeltaVolQuote::AtmType ltat = DeltaVolQuote::AtmType::AtmDeltaNeutral,
ext::optional<DeltaVolQuote::DeltaType> longTermAtmDeltaType = ext::nullopt,
SmileInterpolationMethod interpolationMethod =
SmileInterpolationMethod::Linear,
bool flatStrikeExtrapolation = false,
BlackVolTimeExtrapolation timeExtrapolation =
BlackVolTimeExtrapolation::FlatVolatility);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of default parameters here—@pcaspers, is their order based on your usage patterns? (i.e., are the last ones also the least likely to be passed?)


if (flatStrikeExtrapolation_) {
if (strike < minStrike()) {
v = minStrike();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either this should be v = interpolation_(minStrike(), true) or the whole check should be moved before the call to interpolation_(strike, true); and used to change strike instead.


if (flatStrikeExtrapolation_) {
if (strike < minStrike()) {
return minStrike();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. You want to return the vol corresponding to the min strike, not the min strike itself. I have a feeling we're probably missing a couple of tests for this part?

template <class Interpolator>
void InterpolatedSmileSection<Interpolator>::checkStrikes() {
if (!std::is_sorted(strikes_.begin(), strikes_.end())) {
std::vector<Size> indices(strikes_.size(), 0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't try to fix the input. I'd just raise an exception and let the user sort it out (pun not intended).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants