Quantlib 中的 FX vanilla 看涨期权价格与彭博不符
FX vanilla call price in Quantlib doesn't match Bloomberg
普通欧洲 EURUSD 看涨期权的 Quantlib 价格与彭博 OVML 价格不匹配。
例如对于以下选项 Quantlib 值 =4.60991,BBG 值 =4.6137,错误 =0.0038(虽然它应该是 ~1e-6 差异)
据我所知,波动的时间和贴现或漂移的时间应该根据确切的时期和时间进行调整。例如,贴现期应为结算日至交割日,波动期应为交易日至到期日。考虑到到期时间和交易时间的差异,也应正确表达波动率参数。
但是我在 Quantlib 中没有看到一个选项来说明交货日期与到期日期不同。我如何考虑结算调整(例如,EURUSD 的结算日期为 T+2,即 spot/trade 日期后 2 天,或 USDCAD 的 T+1)和延迟交货调整(交货日期为 T+ 2,即到期后 2 天),如 Clark, Iain J. 外汇期权定价:从业者指南中所述。 John Wiley & Sons,2011 年,第 33 页,
和 "Wystup, Uwe. FX options and structured products. John Wiley & Sons, 2015. p.26-29"
这是 BBG 截图
domestic/foreign 比率(复合式 MMkt):
和代码
int main(){
QuantLib::Real S = 100;
QuantLib::Real K = 105;
QuantLib::Spread f = 0.05;// Foreign rate (EUR in EURUSD)
QuantLib::Rate r = 0.02; // Domestic rate (USD in EURUSD)
QuantLib::Volatility vol = 0.2;
QuantLib::DayCounter dayCounter = Actual365Fixed();
QuantLib::Date evaluationDate = Date(13, Feb, 2018);
QuantLib::Date settlementDate = evaluationDate + Period(2, Days);//T+2 = Date(15, Feb, 2018);
QuantLib::Date expirationDate = settlementDate + Period(1, Years); //Date(15, May, 2019);
Calendar calendar = UnitedStates(UnitedStates::NYSE);
Exercise::Type exerciseType = Exercise::European;
Real result = 4.6137;
Real tol = 1e-3; // tolerance
Option::Type optionType = Option::Call;
Compounding compounding = Compounded;
Frequency compoundingFrequency = Semiannual;
VanillaOptionData vanillaOptionData = { S, K, f, r, vol, dayCounter, evaluationDate, settlementDate,
expirationDate, calendar,exerciseType, result, tol, optionType, compounding, compoundingFrequency };
calculator_fx_vanilla_black_scholes(vanillaOptionData);
//results
//calculated value=4.60991, expected value=4.6137, error=0.00379258
return 0;
}
void calculator_fx_vanilla_black_scholes(VanillaOptionData in)
{
Calendar calendar = TARGET();
Settings::instance().evaluationDate() = in.evaluationDate;
boost::shared_ptr<Exercise> exercise= boost::make_shared<EuropeanExercise>(in.expirationDate);
Handle<Quote>underlyingH(boost::shared_ptr<Quote>(new SimpleQuote(in.S)));
Handle<YieldTermStructure> rTS(boost::shared_ptr<YieldTermStructure>(new FlatForward(in.settlementDate, in.r, in.dayCounter, in.compounding, in.compoundingFrequency)));
Handle<YieldTermStructure> fTS(boost::shared_ptr<YieldTermStructure>(new FlatForward(in.settlementDate, in.f, in.dayCounter, in.compounding, in.compoundingFrequency)));
Handle<BlackVolTermStructure> flatVolTS(boost::shared_ptr<BlackVolTermStructure>(new BlackConstantVol(in.settlementDate, calendar, in.vol, in.dayCounter)));
boost::shared_ptr<StrikedTypePayoff>payoff(new PlainVanillaPayoff(in.optionType, in.K));
boost::shared_ptr<GarmanKohlagenProcess>process(new GarmanKohlagenProcess(underlyingH, fTS, rTS, flatVolTS));
VanillaOption option(payoff, exercise);
boost::shared_ptr<PricingEngine> pe(new AnalyticEuropeanEngine(process));
option.setPricingEngine(pe);
Real calculated = option.NPV();
Real expected = in.result;
Real error = std::fabs(calculated - expected);
cout << "calculated value=" << calculated << ", expected value=" << expected << ", error=" << error << endl;
}
相关:https://quant.stackexchange.com/questions/33604/pricing-of-a-foreign-exchange-vanilla-option
你是对的;目前,无法说明不同的交货日期。作为解决方法,您可以尝试通过到期日和交货日期之间的额外折扣系数来更正价格(您必须将其计算为两个相应折扣系数的比率)。
另一方面,曲线的不同时间(折扣到结算、从交易到到期的波动)可能已经通过处理相应曲线的参考日期获得;像
FlatForward(in.settlementDate, ...)
费率和
BlackConstantVol(in.evaluationDate, ...)
应该适用于使用分析引擎的原始选项(但不适用于有限差分或 Monte Carlo 引擎,不幸的是,它们需要一个共同的时间轴)。
我会尝试上述方法,并在有更多时间时报告我的结果。
我遇到了同样的问题。对于一年 EUR/USD vanilla 看涨期权,通过调用 Quantlib 并遵循 Clark 书中的公式,它将产生略小于 1 个基点的小差异。
经过一些彻底的测试,我能够确定为什么会出现差异。 Quantlib Black Scholes 库使用两个日期进行所有计算,即 evaluation_date(即今天)和 delivery_date。
所以,如果有四个日期:evaluation_date(即今天),SpotDate,expiry_date(即成熟期),delivery_date。 Quantlib Black Scholes 公式将仅假设两个日期,即 delivery_date 的付款,并且所有相关条款都打折回 evaluation_Date。
如果你能接触到源码,cpp文件,d1,d2的实际计算如下图,高亮部分:
请注意,
上面的远期是delivery_date的远期汇率,它是根据evaluation_date的汇率推导出来的,国内和delivery_date和evaluation_date之间的贴现系数国外市场。
stdDev 就是波动率 * sqrt(T)。
最后在同一个文件内计算option的值blackcalculator.cpp,如下:
上图中的折扣是evaluation_date和deivery_date之间的国内折扣系数。这样我们在evaluation_date上得到了最终结果,记为MV_evalDate。这与 Bloomberg 或 Murex 上的值不完全匹配,因为在 Murex 上,它是按现货日期报价的。我们需要将 evaluation_date 的结果转发到现货日期,然后我们得到现货日期的市场价值为 MV_spotDate = MV_evalDate * exp(domestic_rate * timefrac_between_evalDate_spotDate) = MV_evalDate / domestic_discountfactor_evalDate_spotDate。
那么我们就可以得到即期市值的匹配结果,或者Clark的书第32页(2.86)的公式所示的结算调整结果。
普通欧洲 EURUSD 看涨期权的 Quantlib 价格与彭博 OVML 价格不匹配。
例如对于以下选项 Quantlib 值 =4.60991,BBG 值 =4.6137,错误 =0.0038(虽然它应该是 ~1e-6 差异)
据我所知,波动的时间和贴现或漂移的时间应该根据确切的时期和时间进行调整。例如,贴现期应为结算日至交割日,波动期应为交易日至到期日。考虑到到期时间和交易时间的差异,也应正确表达波动率参数。
但是我在 Quantlib 中没有看到一个选项来说明交货日期与到期日期不同。我如何考虑结算调整(例如,EURUSD 的结算日期为 T+2,即 spot/trade 日期后 2 天,或 USDCAD 的 T+1)和延迟交货调整(交货日期为 T+ 2,即到期后 2 天),如 Clark, Iain J. 外汇期权定价:从业者指南中所述。 John Wiley & Sons,2011 年,第 33 页, 和 "Wystup, Uwe. FX options and structured products. John Wiley & Sons, 2015. p.26-29"
这是 BBG 截图
domestic/foreign 比率(复合式 MMkt):
和代码
int main(){
QuantLib::Real S = 100;
QuantLib::Real K = 105;
QuantLib::Spread f = 0.05;// Foreign rate (EUR in EURUSD)
QuantLib::Rate r = 0.02; // Domestic rate (USD in EURUSD)
QuantLib::Volatility vol = 0.2;
QuantLib::DayCounter dayCounter = Actual365Fixed();
QuantLib::Date evaluationDate = Date(13, Feb, 2018);
QuantLib::Date settlementDate = evaluationDate + Period(2, Days);//T+2 = Date(15, Feb, 2018);
QuantLib::Date expirationDate = settlementDate + Period(1, Years); //Date(15, May, 2019);
Calendar calendar = UnitedStates(UnitedStates::NYSE);
Exercise::Type exerciseType = Exercise::European;
Real result = 4.6137;
Real tol = 1e-3; // tolerance
Option::Type optionType = Option::Call;
Compounding compounding = Compounded;
Frequency compoundingFrequency = Semiannual;
VanillaOptionData vanillaOptionData = { S, K, f, r, vol, dayCounter, evaluationDate, settlementDate,
expirationDate, calendar,exerciseType, result, tol, optionType, compounding, compoundingFrequency };
calculator_fx_vanilla_black_scholes(vanillaOptionData);
//results
//calculated value=4.60991, expected value=4.6137, error=0.00379258
return 0;
}
void calculator_fx_vanilla_black_scholes(VanillaOptionData in) {
Calendar calendar = TARGET();
Settings::instance().evaluationDate() = in.evaluationDate;
boost::shared_ptr<Exercise> exercise= boost::make_shared<EuropeanExercise>(in.expirationDate);
Handle<Quote>underlyingH(boost::shared_ptr<Quote>(new SimpleQuote(in.S)));
Handle<YieldTermStructure> rTS(boost::shared_ptr<YieldTermStructure>(new FlatForward(in.settlementDate, in.r, in.dayCounter, in.compounding, in.compoundingFrequency)));
Handle<YieldTermStructure> fTS(boost::shared_ptr<YieldTermStructure>(new FlatForward(in.settlementDate, in.f, in.dayCounter, in.compounding, in.compoundingFrequency)));
Handle<BlackVolTermStructure> flatVolTS(boost::shared_ptr<BlackVolTermStructure>(new BlackConstantVol(in.settlementDate, calendar, in.vol, in.dayCounter)));
boost::shared_ptr<StrikedTypePayoff>payoff(new PlainVanillaPayoff(in.optionType, in.K));
boost::shared_ptr<GarmanKohlagenProcess>process(new GarmanKohlagenProcess(underlyingH, fTS, rTS, flatVolTS));
VanillaOption option(payoff, exercise);
boost::shared_ptr<PricingEngine> pe(new AnalyticEuropeanEngine(process));
option.setPricingEngine(pe);
Real calculated = option.NPV();
Real expected = in.result;
Real error = std::fabs(calculated - expected);
cout << "calculated value=" << calculated << ", expected value=" << expected << ", error=" << error << endl;
}
相关:https://quant.stackexchange.com/questions/33604/pricing-of-a-foreign-exchange-vanilla-option
你是对的;目前,无法说明不同的交货日期。作为解决方法,您可以尝试通过到期日和交货日期之间的额外折扣系数来更正价格(您必须将其计算为两个相应折扣系数的比率)。
另一方面,曲线的不同时间(折扣到结算、从交易到到期的波动)可能已经通过处理相应曲线的参考日期获得;像
FlatForward(in.settlementDate, ...)
费率和
BlackConstantVol(in.evaluationDate, ...)
应该适用于使用分析引擎的原始选项(但不适用于有限差分或 Monte Carlo 引擎,不幸的是,它们需要一个共同的时间轴)。
我会尝试上述方法,并在有更多时间时报告我的结果。
我遇到了同样的问题。对于一年 EUR/USD vanilla 看涨期权,通过调用 Quantlib 并遵循 Clark 书中的公式,它将产生略小于 1 个基点的小差异。
经过一些彻底的测试,我能够确定为什么会出现差异。 Quantlib Black Scholes 库使用两个日期进行所有计算,即 evaluation_date(即今天)和 delivery_date。
所以,如果有四个日期:evaluation_date(即今天),SpotDate,expiry_date(即成熟期),delivery_date。 Quantlib Black Scholes 公式将仅假设两个日期,即 delivery_date 的付款,并且所有相关条款都打折回 evaluation_Date。
如果你能接触到源码,cpp文件,d1,d2的实际计算如下图,高亮部分:
请注意, 上面的远期是delivery_date的远期汇率,它是根据evaluation_date的汇率推导出来的,国内和delivery_date和evaluation_date之间的贴现系数国外市场。 stdDev 就是波动率 * sqrt(T)。
最后在同一个文件内计算option的值blackcalculator.cpp,如下:
上图中的折扣是evaluation_date和deivery_date之间的国内折扣系数。这样我们在evaluation_date上得到了最终结果,记为MV_evalDate。这与 Bloomberg 或 Murex 上的值不完全匹配,因为在 Murex 上,它是按现货日期报价的。我们需要将 evaluation_date 的结果转发到现货日期,然后我们得到现货日期的市场价值为 MV_spotDate = MV_evalDate * exp(domestic_rate * timefrac_between_evalDate_spotDate) = MV_evalDate / domestic_discountfactor_evalDate_spotDate。
那么我们就可以得到即期市值的匹配结果,或者Clark的书第32页(2.86)的公式所示的结算调整结果。