Build the calibration info.
1744 {
1745 DLOG(
"CommodityVolCurve: building volatility calibration info");
1746 try{
1747
1749 bool reportOnDeltaGrid = *rc.reportOnDeltaGrid();
1750 bool reportOnMoneynessGrid = *rc.reportOnMoneynessGrid();
1751 std::vector<Real> moneyness = *rc.moneyness();
1752 std::vector<std::string> deltas = *rc.deltas();
1753 std::vector<Period> expiries = *rc.expiries();
1754
1755
1756 auto info = QuantLib::ext::make_shared<FxEqCommVolCalibrationInfo>();
1757
1758 DeltaVolQuote::AtmType atmType = DeltaVolQuote::AtmType::AtmDeltaNeutral;
1759 DeltaVolQuote::DeltaType deltaType = DeltaVolQuote::DeltaType::Fwd;
1760
1761 if (auto vdsc = QuantLib::ext::dynamic_pointer_cast<VolatilityDeltaSurfaceConfig>(vc)) {
1764 }
1765
1772 info->switchTenor = "na";
1773 info->riskReversalInFavorOf = "na";
1774 info->butterflyStyle = "na";
1775
1776 std::vector<Real> times, forwards;
1777 for (auto const& p : expiries) {
1779 info->expiryDates.push_back(d);
1780 times.push_back(
volatility_->dayCounter().empty() ? Actual365Fixed().yearFraction(asof, d)
1782 forwards.push_back(
pts_->price(d));
1783 }
1784
1785 info->times = times;
1786 info->forwards = forwards;
1787 std::vector<std::vector<Real>> callPricesDelta(times.size(), std::vector<Real>(deltas.size(), 0.0));
1788 if (reportOnDeltaGrid) {
1789 info->deltas = deltas;
1790 info->deltaCallPrices =
1791 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1792 info->deltaPutPrices =
1793 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1794 info->deltaGridStrikes =
1795 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1796 info->deltaGridProb = std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1797 info->deltaGridImpliedVolatility =
1798 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(deltas.size(), 0.0));
1799 info->deltaGridCallSpreadArbitrage =
1800 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(deltas.size(), true));
1801 info->deltaGridButterflyArbitrage =
1802 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(deltas.size(), true));
1803
1804 Real maxTime = QL_MAX_REAL;
1807 maxTime = Actual365Fixed().yearFraction(asof,
maxExpiry_);
1808 else
1810 }
1811
1812 DeltaVolQuote::AtmType at;
1813 DeltaVolQuote::DeltaType dt;
1814 for (Size i = 0; i < times.size(); ++i) {
1815 Real t = times[i];
1816 at = atmType;
1817 dt = deltaType;
1818
1819
1820 if (t > maxTime) {
1821 at = DeltaVolQuote::AtmDeltaNeutral;
1822 dt = DeltaVolQuote::Fwd;
1823 }
1824 bool validSlice = true;
1825 for (Size j = 0; j < deltas.size(); ++j) {
1826 DeltaString d(deltas[j]);
1827 try {
1828 Real strike;
1829 if (d.isAtm()) {
1830 strike =
1832 } else if (d.isCall()) {
1835 } else {
1838 }
1839 Real stddev = std::sqrt(
volatility_->blackVariance(t, strike));
1840 callPricesDelta[i][j] = QuantExt::blackFormula(Option::Call, strike, forwards[i], stddev);
1841
1842 if (d.isPut()) {
1843 info->deltaPutPrices[i][j] = blackFormula(Option::Put, strike, forwards[i], stddev,
yts_->discount(t));
1844 } else {
1845 info->deltaCallPrices[i][j] = blackFormula(Option::Call, strike, forwards[i], stddev,
yts_->discount(t));
1846 }
1847
1848 info->deltaGridStrikes[i][j] = strike;
1849 info->deltaGridImpliedVolatility[i][j] = stddev / std::sqrt(t);
1850 } catch (const std::exception& e) {
1851 validSlice = false;
1852 TLOG(
"CommodityVolCurve: error for time " << t <<
" delta " << deltas[j] <<
": " << e.what());
1853 }
1854 }
1855 if (validSlice) {
1856 try {
1858 callPricesDelta[i]);
1859 info->deltaGridCallSpreadArbitrage[i] = cm.callSpreadArbitrage();
1860 info->deltaGridButterflyArbitrage[i] = cm.butterflyArbitrage();
1861 if (!cm.arbitrageFree())
1862 info->isArbitrageFree = false;
1863 info->deltaGridProb[i] = cm.density();
1865 } catch (const std::exception& e) {
1866 TLOG(
"error for time " << t <<
": " << e.what());
1867 info->isArbitrageFree = false;
1869 }
1870 } else {
1871 info->isArbitrageFree = false;
1873 }
1874 }
1875 TLOG(
"CommodityVolCurve: Delta surface arbitrage analysis completed.");
1876 }
1877 std::vector<std::vector<Real>> callPricesMoneyness(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1878 if (reportOnMoneynessGrid) {
1879 info->moneyness = moneyness;
1880 info->moneynessCallPrices =
1881 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1882 info->moneynessPutPrices =
1883 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1884 info->moneynessGridStrikes =
1885 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1886 info->moneynessGridProb =
1887 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1888 info->moneynessGridImpliedVolatility =
1889 std::vector<std::vector<Real>>(times.size(), std::vector<Real>(moneyness.size(), 0.0));
1890 info->moneynessGridCallSpreadArbitrage =
1891 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(moneyness.size(), true));
1892 info->moneynessGridButterflyArbitrage =
1893 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(moneyness.size(), true));
1894 info->moneynessGridCalendarArbitrage =
1895 std::vector<std::vector<bool>>(times.size(), std::vector<bool>(moneyness.size(), true));
1896 for (Size i = 0; i < times.size(); ++i) {
1897 Real t = times[i];
1898 for (Size j = 0; j < moneyness.size(); ++j) {
1899 try {
1900 Real strike = moneyness[j] * forwards[i];
1901 info->moneynessGridStrikes[i][j] = strike;
1902 Real stddev = std::sqrt(
volatility_->blackVariance(t, strike));
1903 callPricesMoneyness[i][j] = blackFormula(Option::Call, strike, forwards[i], stddev);
1904 info->moneynessGridImpliedVolatility[i][j] = stddev / std::sqrt(t);
1905 if (moneyness[j] >= 1) {
1906 calibrationInfo_->moneynessCallPrices[i][j] = blackFormula(Option::Call, strike, forwards[i], stddev,
yts_->discount(t));
1907 } else {
1908 calibrationInfo_->moneynessPutPrices[i][j] = blackFormula(Option::Put, strike, forwards[i], stddev,
yts_->discount(t));
1909 };
1910 } catch (const std::exception& e) {
1911 TLOG(
"CommodityVolCurve: error for time " << t <<
" moneyness " << moneyness[j] <<
": " << e.what());
1912 }
1913 }
1914 }
1915 if (!times.empty() && !moneyness.empty()) {
1916 try {
1918 callPricesMoneyness);
1919 for (Size i = 0; i < times.size(); ++i) {
1920 info->moneynessGridProb[i] = cm.timeSlices()[i].density();
1921 }
1922 info->moneynessGridCallSpreadArbitrage = cm.callSpreadArbitrage();
1923 info->moneynessGridButterflyArbitrage = cm.butterflyArbitrage();
1924 info->moneynessGridCalendarArbitrage = cm.calendarArbitrage();
1925 if (!cm.arbitrageFree())
1926 info->isArbitrageFree = false;
1927 TLOG(
"CommodityVolCurve: Moneyness surface Arbitrage analysis result:");
1929 } catch (const std::exception& e) {
1930 TLOG(
"CommodityVolCurve: error: " << e.what());
1931 info->isArbitrageFree = false;
1932 }
1933 TLOG(
"CommodityVolCurve: Moneyness surface Arbitrage analysis completed:");
1934 }
1935 }
1937 }
1938 catch (std::exception& e){
1939 QL_FAIL("CommodityVolCurve: calibration info building failed: " << e.what());
1940 } catch (...) {
1941 QL_FAIL("CommodityVolCurve: calibration info building failed: unknown error");
1942 }
1943 }
QuantLib::Handle< QuantExt::PriceTermStructure > pts_
QuantLib::ext::shared_ptr< FxEqCommVolCalibrationInfo > calibrationInfo_
QuantLib::Date maxExpiry_
QuantLib::Calendar calendar_
QuantLib::Handle< QuantLib::YieldTermStructure > yts_
QuantLib::DayCounter dayCounter_
DeltaVolQuote::AtmType parseAtmType(const std::string &s)
Convert text to QuantLib::DeltaVolQuote::AtmType.
DeltaVolQuote::DeltaType parseDeltaType(const std::string &s)
Convert text to QuantLib::DeltaVolQuote::DeltaType.
#define DLOG(text)
Logging Macro (Level = Debug)
#define TLOGGERSTREAM(text)
#define TLOG(text)
Logging Macro (Level = Data)
Real getAtmStrike(DeltaVolQuote::DeltaType dt, DeltaVolQuote::AtmType at, Real spot, Real domDiscount, Real forDiscount, boost::shared_ptr< BlackVolTermStructure > vol, Real t, Real accuracy, Size maxIterations)
std::string arbitrageAsString(const CarrMadanMarginalProbabilityClass &cm)
Real getStrikeFromDelta(Option::Type optionType, Real delta, DeltaVolQuote::DeltaType dt, Real spot, Real domDiscount, Real forDiscount, boost::shared_ptr< BlackVolTermStructure > vol, Real t, Real accuracy, Size maxIterations)
ReportConfig effectiveReportConfig(const ReportConfig &globalConfig, const ReportConfig &localConfig)
std::string to_string(const LocationInfo &l)
vector< string > curveConfigs