21#include <boost/make_shared.hpp>
22#include <boost/test/unit_test.hpp>
23#include <boost/test/data/test_case.hpp>
24#include <oret/datapaths.hpp>
30#include <oret/toplevelfixture.hpp>
31#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
32#include <ql/termstructures/yield/flatforward.hpp>
33#include <ql/time/daycounters/actualactual.hpp>
38using namespace boost::unit_test_framework;
42BOOST_FIXTURE_TEST_SUITE(OREDataPlusTestSuite, ore::test::TopLevelFixture)
44BOOST_AUTO_TEST_SUITE(CompositeTradeTest)
50 TestMarket(map<
string, Handle<Quote>> fxRates = {{
"EURUSD", Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.2))}})
52 asof_ = Date(3, Feb, 2016);
59 std::map<std::string, QuantLib::Handle<QuantLib::Quote>> quotes;
60 for (
auto& fxRate : fxRates) {
63 fx_ = QuantLib::ext::make_shared<FXTriangulation>(quotes);
70 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(100));
72 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(100));
82 Handle<EquityIndex2>(QuantLib::ext::make_shared<EquityIndex2>(
84 yieldCurve(YieldCurveType::Discount,
"EUR"),
yieldCurve(YieldCurveType::EquityDividend,
"eurCorp")));
86 Handle<EquityIndex2>(QuantLib::ext::make_shared<EquityIndex2>(
88 yieldCurve(YieldCurveType::Discount,
"USD"),
yieldCurve(YieldCurveType::EquityDividend,
"usdCorp")));
96 Handle<YieldTermStructure> flatRateYts(Real forward) {
97 QuantLib::ext::shared_ptr<YieldTermStructure> yts(
new FlatForward(0, NullCalendar(), forward, ActualActual(ActualActual::ISDA)));
98 return Handle<YieldTermStructure>(yts);
100 Handle<BlackVolTermStructure> flatRateFxv(Volatility forward) {
101 QuantLib::ext::shared_ptr<BlackVolTermStructure> fxv(
new BlackConstantVol(0, NullCalendar(), forward, ActualActual(ActualActual::ISDA)));
102 return Handle<BlackVolTermStructure>(fxv);
109 BOOST_TEST_MESSAGE(
"Testing SyntheticForwardTrade...");
111 SavedSettings backup;
113 InstrumentConventions::instance().setConventions(QuantLib::ext::make_shared<Conventions>());
116 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>();
117 Settings::instance().evaluationDate() = market->asofDate();
118 Date expiry = market->asofDate() + 6 * Months + 1 * Days;
120 o << QuantLib::io::iso_date(expiry);
121 string exp_str = o.str();
124 OptionData callData(
"Long",
"Call",
"European",
true, vector<string>(1, exp_str));
125 OptionData putData(
"Short",
"Put",
"European",
true, vector<string>(1, exp_str));
128 QuantLib::ext::shared_ptr<Trade> eqCall =
129 QuantLib::ext::make_shared<EquityOption>(env, callData,
EquityUnderlying(
"eurCorp"),
"EUR", 1.0, tradeStrike);
130 eqCall->id() =
"Long Call";
131 QuantLib::ext::shared_ptr<Trade> eqPut =
132 QuantLib::ext::make_shared<EquityOption>(env, putData,
EquityUnderlying(
"eurCorp"),
"EUR", 1.0, tradeStrike);
133 eqPut->id() =
"Short Put";
134 CompositeTrade syntheticForward(
"EUR", {eqCall, eqPut},
"Mean", 0.0, env);
135 syntheticForward.
id() =
"Synthetic Forward Test";
139 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
140 engineData->model(
"EquityOption") =
"BlackScholesMerton";
141 engineData->engine(
"EquityOption") =
"AnalyticEuropeanEngine";
142 engineData->model(
"EquityForward") =
"DiscountedCashflows";
143 engineData->engine(
"EquityForward") =
"DiscountingEquityForwardEngine";
144 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
146 syntheticForward.build(engineFactory);
147 eqFwd.build(engineFactory);
149 Real npv_composite = syntheticForward.instrument()->NPV();
150 Real npv_fwd = eqFwd.instrument()->NPV();
152 BOOST_CHECK_CLOSE(npv_composite, npv_fwd, 0.01);
153 BOOST_CHECK_CLOSE(syntheticForward.notional(), eqFwd.notional(), 0.01);
158 BOOST_TEST_MESSAGE(
"Testing SyntheticForwardTrade...");
160 SavedSettings backup;
162 InstrumentConventions::instance().setConventions(QuantLib::ext::make_shared<Conventions>());
165 QuantLib::ext::shared_ptr<SimpleQuote> eurusdRate(QuantLib::ext::make_shared<SimpleQuote>(1.2));
166 map<string, Handle<Quote>> fxRates = {{
"EURUSD", Handle<Quote>(eurusdRate)}};
167 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>(fxRates);
168 Settings::instance().evaluationDate() = market->asofDate();
169 Date expiry = market->asofDate() + 6 * Months + 1 * Days;
171 o << QuantLib::io::iso_date(expiry);
172 string exp_str = o.str();
175 OptionData callData(
"Long",
"Call",
"European",
true, vector<string>(1, exp_str));
178 QuantLib::ext::shared_ptr<Trade> eurCall =
179 QuantLib::ext::make_shared<EquityOption>(env, callData,
EquityUnderlying(
"eurCorp"),
"EUR", 1.0, tradeStrike_EUR);
180 eurCall->id() =
"EUR Call";
182 QuantLib::ext::shared_ptr<Trade> usdCall =
183 QuantLib::ext::make_shared<EquityOption>(env, callData,
EquityUnderlying(
"usdCorp"),
"USD", 1.0, tradeStrike_USD);
184 usdCall->id() =
"USD Call";
185 CompositeTrade eurComp(
"EUR", {eurCall, usdCall},
"Sum", 0.0, env);
186 CompositeTrade usdComp(
"USD", {eurCall, usdCall},
"Sum", 0.0, env);
187 eurComp.
id() =
"EUR Combo Call Test";
188 usdComp.id() =
"USD Combo Call Test";
191 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
192 engineData->model(
"EquityOption") =
"BlackScholesMerton";
193 engineData->engine(
"EquityOption") =
"AnalyticEuropeanEngine";
194 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
196 eurComp.build(engineFactory);
197 usdComp.build(engineFactory);
199 Real npv_eur_composite = eurComp.instrument()->NPV();
200 Real npv_usd_composite = usdComp.instrument()->NPV();
201 Real npv_eurCall = eurCall->instrument()->NPV();
202 Real npv_usdCall = usdCall->instrument()->NPV();
204 BOOST_CHECK_CLOSE(npv_eur_composite, npv_eurCall * 1.0 + npv_usdCall / 1.2, 0.01);
205 BOOST_CHECK_CLOSE(npv_usd_composite, npv_eurCall * 1.2 + npv_usdCall / 1.0, 0.01);
207 BOOST_CHECK_CLOSE(usdComp.notional(), eurCall->notional() * 2.2, 0.01);
210 auto testMarket = QuantLib::ext::dynamic_pointer_cast<TestMarket>(market);
211 eurusdRate->setValue(1.25);
212 npv_usd_composite = usdComp.instrument()->NPV();
213 BOOST_CHECK_CLOSE(npv_usd_composite, npv_eurCall * 1.25 + npv_usdCall / 1.0, 0.01);
217 BOOST_TEST_MESSAGE(
"Testing Composite Trade with and w/o reference data...");
219 SavedSettings backup;
221 InstrumentConventions::instance().setConventions(QuantLib::ext::make_shared<Conventions>());
224 auto rdm = QuantLib::ext::make_shared<BasicReferenceDataManager>(TEST_INPUT_FILE(
"reference_data.xml"));
225 auto ptfReferenceDatum = QuantLib::ext::dynamic_pointer_cast<PortfolioBasketReferenceDatum>(rdm->getData(
"PortfolioBasket",
"MSFDSJP"));
226 auto refData = ptfReferenceDatum->getTrades();
227 QuantLib::ext::shared_ptr<Trade> eqRefCall = refData[0];
228 QuantLib::ext::shared_ptr<Trade> eqRefPut = refData[1];
231 CompositeTrade RefData(
"EUR", {eqRefCall, eqRefPut},
"Mean", 0.0, env);
232 RefData.
id() =
"Reference Data Test";
235 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>();
236 Settings::instance().evaluationDate() = market->asofDate();
237 Date expiry = market->asofDate() + 6 * Months + 1 * Days;
239 o << QuantLib::io::iso_date(expiry);
240 string exp_str = o.str();
243 OptionData callData(
"Long",
"Call",
"European",
true, vector<string>(1, exp_str));
244 OptionData putData(
"Short",
"Put",
"European",
true, vector<string>(1, exp_str));
247 QuantLib::ext::shared_ptr<Trade> eqCall =
248 QuantLib::ext::make_shared<EquityOption>(env, callData,
EquityUnderlying(
"eurCorp"),
"EUR", 1.0, tradeStrike);
249 eqCall->id() =
"Long Call";
250 QuantLib::ext::shared_ptr<Trade> eqPut =
251 QuantLib::ext::make_shared<EquityOption>(env, putData,
EquityUnderlying(
"eurCorp"),
"EUR", 1.0, tradeStrike);
252 eqPut->id() =
"Short Put";
253 CompositeTrade noRefData(
"EUR", {eqCall, eqPut},
"Mean", 0.0, env);
254 noRefData.
id() =
"No Reference Data Test";
257 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
258 engineData->model(
"EquityOption") =
"BlackScholesMerton";
259 engineData->engine(
"EquityOption") =
"AnalyticEuropeanEngine";
260 QuantLib::ext::shared_ptr<EngineFactory> engineFactory =
261 QuantLib::ext::make_shared<EngineFactory>(engineData, market);
263 noRefData.build(engineFactory);
264 RefData.build(engineFactory);
266 Real npv_composite_NoRefData = noRefData.instrument()->NPV();
267 Real npv_composite_RefData = RefData.instrument()->NPV();
269 BOOST_CHECK_CLOSE(npv_composite_NoRefData, npv_composite_RefData, 0.01);
270 BOOST_CHECK_CLOSE(noRefData.notional(), RefData.notional(), 0.01);
276 auto rdm = QuantLib::ext::make_shared<BasicReferenceDataManager>(TEST_INPUT_FILE(
"reference_data.xml"));
277 auto ptfReferenceDatum =
278 QuantLib::ext::dynamic_pointer_cast<PortfolioBasketReferenceDatum>(rdm->getData(
"PortfolioBasket",
"MSFDSJP"));
280 string xmlRefData = ptfReferenceDatum->toXMLString();
284 BOOST_CHECK_EQUAL(ptfReferenceDatum->id(), xmlPortfolioBasket.
id());
285 BOOST_CHECK_EQUAL(ptfReferenceDatum->getTrades()[0]->notional(), xmlPortfolioBasket.
getTrades()[0]->notional());
286 BOOST_CHECK_EQUAL(ptfReferenceDatum->getTrades()[1]->notional(), xmlPortfolioBasket.
getTrades()[1]->notional());
287 BOOST_CHECK_EQUAL(ptfReferenceDatum->getTrades()[0]->id(), xmlPortfolioBasket.
getTrades()[0]->id());
288 BOOST_CHECK_EQUAL(ptfReferenceDatum->getTrades()[1]->id(), xmlPortfolioBasket.
getTrades()[1]->id());
290 auto refData = ptfReferenceDatum->getTrades();
291 QuantLib::ext::shared_ptr<Trade> eqRefCall = refData[0];
292 QuantLib::ext::shared_ptr<Trade> eqRefPut = refData[1];
295 CompositeTrade compRefData(
"EUR", {eqRefCall, eqRefPut},
"Mean", 0.0, env);
302 BOOST_CHECK_EQUAL(compRefData.id(), xmlComposite.
id());
303 BOOST_CHECK_EQUAL(compRefData.currency(), xmlComposite.
currency());
305 BOOST_CHECK_EQUAL(compRefData.trades()[0]->tradeType(), xmlComposite.
trades()[0]->tradeType());
306 BOOST_CHECK_EQUAL(compRefData.trades()[0]->notional(), xmlComposite.
trades()[0]->notional());
307 BOOST_CHECK_EQUAL(compRefData.trades()[1]->tradeType(), xmlComposite.
trades()[1]->tradeType());
308 BOOST_CHECK_EQUAL(compRefData.trades()[1]->notional(), xmlComposite.
trades()[1]->notional());
313BOOST_AUTO_TEST_SUITE_END()
315BOOST_AUTO_TEST_SUITE_END()
Builder that returns an engine to price an equity forward.
Engine builder for equity options.
const string & currency() const
const vector< QuantLib::ext::shared_ptr< Trade > > & trades() const
const string & notionalCalculation() const
Serializable object holding generic trade data, reporting dimensions.
Handle< Quote > fxRate(const string &ccypair, const string &configuration=Market::defaultConfiguration) const
static const string defaultConfiguration
Default configuration label.
map< pair< string, string >, QuantLib::Handle< QuantExt::EquityIndex2 > > equityCurves_
map< pair< string, string >, Handle< BlackVolTermStructure > > fxVols_
QuantLib::ext::shared_ptr< FXTriangulation > fx_
map< tuple< string, YieldCurveType, string >, Handle< YieldTermStructure > > yieldCurves_
map< pair< string, string >, Handle< Quote > > equitySpots_
Handle< Quote > equitySpot(const string &eqName, const string &configuration=Market::defaultConfiguration) const override
Equity curves.
map< pair< string, string >, Handle< BlackVolTermStructure > > equityVols_
Handle< YieldTermStructure > yieldCurve(const YieldCurveType &type, const string &ccy, const string &configuration=Market::defaultConfiguration) const override
Yield Curves.
Serializable object holding option data.
const vector< QuantLib::ext::shared_ptr< Trade > > & getTrades() const
const std::string & id() const
string & id()
Set the trade id.
std::string toXMLString() const
Parse from XML string.
void fromXMLString(const std::string &xml)
Parse from XML string.
Composite trades operate as a mini portfolio. Their intended use is for strategies like straddles.
Equity Forward data model and serialization.
Equity Option data model and serialization.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
An implementation of the Market class that stores the required objects in maps.
BOOST_AUTO_TEST_CASE(testSyntheticForward)