@@ -2413,87 +2413,57 @@ XMLNode* ZeroInflationIndexConvention::toXML(XMLDocument& doc) {
24132413}
24142414
24152415void Conventions::fromXML (XMLNode* node) {
2416-
24172416 XMLUtils::checkNode (node, " Conventions" );
24182417
24192418 for (XMLNode* child = XMLUtils::getChildNode (node); child; child = XMLUtils::getNextSibling (child)) {
24202419
2420+ string type = XMLUtils::getNodeName (child);
24212421 boost::shared_ptr<Convention> convention;
2422- string childName = XMLUtils::getNodeName (child);
2423-
2424- // Some conventions depend on the already read conventions, since they parse an ibor or overnight
2425- // index which may be convention based. In this case we require the index convention to appear
2426- // before the convention that depends on it in the input.
2427-
2428- if (childName == " Zero" ) {
2429- convention.reset (new ZeroRateConvention ());
2430- } else if (childName == " Deposit" ) {
2431- convention.reset (new DepositConvention ());
2432- } else if (childName == " Future" ) {
2433- convention.reset (new FutureConvention ());
2434- } else if (childName == " FRA" ) {
2435- convention.reset (new FraConvention ());
2436- } else if (childName == " OIS" ) {
2437- convention.reset (new OisConvention ());
2438- } else if (childName == " Swap" ) {
2439- convention.reset (new IRSwapConvention ());
2440- } else if (childName == " AverageOIS" ) {
2441- convention.reset (new AverageOisConvention ());
2442- } else if (childName == " TenorBasisSwap" ) {
2443- convention.reset (new TenorBasisSwapConvention ());
2444- } else if (childName == " TenorBasisTwoSwap" ) {
2445- convention.reset (new TenorBasisTwoSwapConvention ());
2446- } else if (childName == " BMABasisSwap" ) {
2447- convention.reset (new BMABasisSwapConvention ());
2448- } else if (childName == " FX" ) {
2449- convention.reset (new FXConvention ());
2450- } else if (childName == " CrossCurrencyBasis" ) {
2451- convention.reset (new CrossCcyBasisSwapConvention ());
2452- } else if (childName == " CrossCurrencyFixFloat" ) {
2453- convention.reset (new CrossCcyFixFloatSwapConvention ());
2454- } else if (childName == " CDS" ) {
2455- convention.reset (new CdsConvention ());
2456- } else if (childName == " SwapIndex" ) {
2457- convention.reset (new SwapIndexConvention ());
2458- } else if (childName == " InflationSwap" ) {
2459- convention.reset (new InflationSwapConvention ());
2460- } else if (childName == " CmsSpreadOption" ) {
2461- convention.reset (new CmsSpreadOptionConvention ());
2462- } else if (childName == " CommodityForward" ) {
2463- convention = boost::make_shared<CommodityForwardConvention>();
2464- } else if (childName == " CommodityFuture" ) {
2465- convention = boost::make_shared<CommodityFutureConvention>();
2466- } else if (childName == " FxOption" ) {
2467- convention = boost::make_shared<FxOptionConvention>();
2468- } else if (childName == " IborIndex" ) {
2422+
2423+ /* we need to build conventions of type
2424+
2425+ - IborIndex
2426+ - OvernightIndex
2427+ - FX
2428+
2429+ immediately because
2430+
2431+ - for IborIndex other conventions depend on it via parseIborIndex() calls
2432+ - the id of IborIndex convention is changed during build (period is normalized)
2433+ - FX conventions are searched by currencies, not id */
2434+
2435+ if (type == " IborIndex" ) {
24692436 convention = boost::make_shared<IborIndexConvention>();
2470- } else if (childName == " OvernightIndex" ) {
2437+ } else if (type == " FX" ) {
2438+ convention = boost::make_shared<FXConvention>();
2439+ } else if (type == " OvernightIndex" ) {
24712440 convention = boost::make_shared<OvernightIndexConvention>();
2472- } else if (childName == " ZeroInflationIndex" ) {
2473- convention = boost::make_shared<ZeroInflationIndexConvention>();
2474- } else if (childName == " BondYield" ) {
2475- convention = boost::make_shared<BondYieldConvention>();
2476- } else {
2477- // No need to QL_FAIL here, just go to the next one
2478- WLOG (" Convention name, " << childName << " , not recognized." );
2479- continue ;
24802441 }
24812442
2482- string id = XMLUtils::getChildValue (child, " Id" , true );
2483-
2484- try {
2485- DLOG (" Loading Convention " << id);
2486- convention->fromXML (child);
2487- add (convention);
2488- } catch (exception& e) {
2489- WLOG (" Exception parsing convention "
2490- " XML Node (id = "
2491- << id << " ) : " << e.what ());
2443+ string id = " unknown" ;
2444+ if (convention) {
2445+ try {
2446+ id = XMLUtils::getChildValue (child, " Id" , true );
2447+ convention->fromXML (child);
2448+ add (convention);
2449+ } catch (const std::exception& e) {
2450+ WLOG (" Exception parsing convention "
2451+ << id << " : " << e.what () << " . This is only a problem if this convention is used later on." );
2452+ }
2453+ } else {
2454+ try {
2455+ id = XMLUtils::getChildValue (child, " Id" , true );
2456+ unparsed_[id] = std::make_pair (type, XMLUtils::toString (child));
2457+ } catch (const std::exception& e) {
2458+ WLOG (" Exception during retrieval of convention "
2459+ << id << " : " << e.what () << " . This is only a problem if this convention is used later on." );
2460+ }
24922461 }
24932462 }
24942463}
24952464
24962465XMLNode* Conventions::toXML (XMLDocument& doc) {
2466+ boost::unique_lock<boost::shared_mutex> lock (mutex_);
24972467
24982468 XMLNode* conventionsNode = doc.allocNode (" Conventions" );
24992469
@@ -2509,33 +2479,109 @@ void Conventions::clear() {
25092479 data_.clear ();
25102480}
25112481
2512- std::string flip (const std::string& id, const std::string& sep) {
2513- boost::tokenizer<boost::escaped_list_separator<char >> tokenSplit (id, boost::escaped_list_separator<char >(" \\ " , sep, " \" " ));
2482+ namespace {
2483+ std::string flip (const std::string& id, const std::string& sep = " -" ) {
2484+ boost::tokenizer<boost::escaped_list_separator<char >> tokenSplit (
2485+ id, boost::escaped_list_separator<char >(" \\ " , sep, " \" " ));
25142486 std::vector<std::string> tokens (tokenSplit.begin (), tokenSplit.end ());
2515- if (tokens.size () >= 2 && tokens[0 ].size () == 3 && tokens[1 ].size () == 3 ) {
2516- std::string id2 = tokens[1 ] + sep + tokens[0 ];
2517- for (Size i = 2 ; i < tokens.size (); ++i)
2518- id2 += sep + tokens[i];
2519- return id2; // flipped id
2487+
2488+ bool eligible = false ;
2489+ for (auto const & t : tokens) {
2490+ eligible = eligible || (t == " XCCY" || t == " FX" || t == " FXOPTION" );
25202491 }
2521- else return id; // original id
2492+
2493+ if (eligible && (tokens.size () > 2 && tokens[0 ].size () == 3 && tokens[1 ].size () == 3 )) {
2494+ std::string id2 = tokens[1 ] + sep + tokens[0 ];
2495+ for (Size i = 2 ; i < tokens.size (); ++i)
2496+ id2 += sep + tokens[i];
2497+ return id2;
2498+ }
2499+
2500+ return id;
25222501}
2523-
2502+ }
2503+
25242504boost::shared_ptr<Convention> Conventions::get (const string& id) const {
2525- boost::shared_lock<boost::shared_mutex> lock (mutex_);
2526- auto it = data_.find (id);
2527- if (it != data_.end ())
2528- return it->second ;
2529- else {
2530- std::string id2 = flip (id);
2531- auto it = data_.find (id2);
2532- if (it != data_.end () && boost::dynamic_pointer_cast<CrossCcyBasisSwapConvention>(it->second )) {
2533- return it->second ;
2534- }
2535- else {
2536- QL_FAIL (" Cannot find conventions for id " << id);
2537- }
2505+
2506+ {
2507+ boost::shared_lock<boost::shared_mutex> lock (mutex_);
2508+ if (auto it = data_.find (id); it != data_.end ())
2509+ return it->second ;
2510+ if (auto it = data_.find (flip (id)); it != data_.end ())
2511+ return it->second ;
25382512 }
2513+
2514+ boost::unique_lock<boost::shared_mutex> lock (mutex_);
2515+
2516+ std::string type, unparsed;
2517+ if (auto it = unparsed_.find (id); it != unparsed_.end ()) {
2518+ std::tie (type, unparsed) = it->second ;
2519+ unparsed_.erase (id);
2520+ } else if (auto it = unparsed_.find (flip (id)); it != unparsed_.end ()) {
2521+ std::tie (type, unparsed) = it->second ;
2522+ unparsed_.erase (flip (id));
2523+ }
2524+
2525+ if (unparsed.empty ()) {
2526+ QL_FAIL (" Required convention '" << id << " ' not found." );
2527+ }
2528+
2529+ boost::shared_ptr<Convention> convention;
2530+ if (type == " Zero" ) {
2531+ convention = boost::make_shared<ZeroRateConvention>();
2532+ } else if (type == " Deposit" ) {
2533+ convention = boost::make_shared<DepositConvention>();
2534+ } else if (type == " Future" ) {
2535+ convention = boost::make_shared<FutureConvention>();
2536+ } else if (type == " FRA" ) {
2537+ convention = boost::make_shared<FraConvention>();
2538+ } else if (type == " OIS" ) {
2539+ convention = boost::make_shared<OisConvention>();
2540+ } else if (type == " Swap" ) {
2541+ convention = boost::make_shared<IRSwapConvention>();
2542+ } else if (type == " AverageOIS" ) {
2543+ convention = boost::make_shared<AverageOisConvention>();
2544+ } else if (type == " TenorBasisSwap" ) {
2545+ convention = boost::make_shared<TenorBasisSwapConvention>();
2546+ } else if (type == " TenorBasisTwoSwap" ) {
2547+ convention=boost::make_shared<TenorBasisTwoSwapConvention>();
2548+ } else if (type == " BMABasisSwap" ) {
2549+ convention = boost::make_shared<BMABasisSwapConvention>();
2550+ } else if (type == " CrossCurrencyBasis" ) {
2551+ convention=boost::make_shared<CrossCcyBasisSwapConvention>();
2552+ } else if (type == " CrossCurrencyFixFloat" ) {
2553+ convention=boost::make_shared<CrossCcyFixFloatSwapConvention>();
2554+ } else if (type == " CDS" ) {
2555+ convention=boost::make_shared<CdsConvention>();
2556+ } else if (type == " SwapIndex" ) {
2557+ convention=boost::make_shared<SwapIndexConvention>();
2558+ } else if (type == " InflationSwap" ) {
2559+ convention=boost::make_shared<InflationSwapConvention>();
2560+ } else if (type == " CmsSpreadOption" ) {
2561+ convention=boost::make_shared<CmsSpreadOptionConvention>();
2562+ } else if (type == " CommodityForward" ) {
2563+ convention = boost::make_shared<CommodityForwardConvention>();
2564+ } else if (type == " CommodityFuture" ) {
2565+ convention = boost::make_shared<CommodityFutureConvention>();
2566+ } else if (type == " FxOption" ) {
2567+ convention = boost::make_shared<FxOptionConvention>();
2568+ } else if (type == " ZeroInflationIndex" ) {
2569+ convention = boost::make_shared<ZeroInflationIndexConvention>();
2570+ } else if (type == " BondYield" ) {
2571+ convention = boost::make_shared<BondYieldConvention>();
2572+ } else {
2573+ QL_FAIL (" Required convention '" << id << " ' has unknown type '" + type + " ' not recognized." );
2574+ }
2575+
2576+ try {
2577+ DLOG (" Loading Convention " << id);
2578+ convention->fromXMLString (unparsed);
2579+ addInternal (convention);
2580+ } catch (exception& e) {
2581+ QL_FAIL (" Required convention '" << id << " ' could not be built: " << e.what ());
2582+ }
2583+
2584+ return convention;
25392585}
25402586
25412587boost::shared_ptr<Convention> Conventions::getFxConvention (const string& ccy1, const string& ccy2) const {
@@ -2549,39 +2595,44 @@ boost::shared_ptr<Convention> Conventions::getFxConvention(const string& ccy1, c
25492595 return fxCon;
25502596 }
25512597 }
2552- QL_FAIL (" Cannot find FX conventions for ccys " << ccy1 << " and " << ccy2);
2598+ QL_FAIL (" Required FX convention for ccys ' " << ccy1 << " ' and ' " << ccy2 << " ' not found. " );
25532599}
25542600
25552601pair<bool , boost::shared_ptr<Convention>> Conventions::get (const string& id, const Convention::Type& type) const {
2556- boost::shared_lock<boost::shared_mutex> lock (mutex_);
2557- auto c = data_.find (id);
2558- if (c == data_.end () || c->second ->type () != type)
2559- return make_pair (false , nullptr );
2560- else
2561- return make_pair (true , c->second );
2602+ try {
2603+ auto c = get (id);
2604+ if (c->type () == type)
2605+ return std::make_pair (true , c);
2606+ } catch (...) {
2607+ }
2608+ return make_pair (false , nullptr );
25622609}
25632610
25642611std::set<boost::shared_ptr<Convention>> Conventions::get (const Convention::Type& type) const {
2565- boost::shared_lock<boost::shared_mutex> lock (mutex_);
25662612 std::set<boost::shared_ptr<Convention>> result;
2567- for (auto const & d : data_) {
2568- if (d.second ->type () == type)
2569- result.insert (d.second );
2613+ std::set<std::string> unparsedIds;
2614+ std::string typeStr = ore::data::to_string (type);
2615+ {
2616+ boost::shared_lock<boost::shared_mutex> lock (mutex_);
2617+ for (auto const & d : data_) {
2618+ if (d.second ->type () == type)
2619+ result.insert (d.second );
2620+ }
2621+ for (auto const & u : unparsed_) {
2622+ if (u.second .first == typeStr)
2623+ unparsedIds.insert (u.first );
2624+ }
2625+ }
2626+ for (auto const & id : unparsedIds) {
2627+ result.insert (get (id));
25702628 }
25712629 return result;
25722630}
25732631
25742632bool Conventions::has (const string& id) const {
25752633 boost::shared_lock<boost::shared_mutex> lock (mutex_);
2576- if (data_.find (id) != data_.end ())
2577- return true ;
2578- else {
2579- std::string id2 = flip (id);
2580- if (data_.find (id2) != data_.end ())
2581- return true ;
2582- else
2583- return false ;
2584- }
2634+ return data_.find (id) != data_.end () || unparsed_.find (id) != unparsed_.end () ||
2635+ data_.find (flip (id)) != data_.end () || unparsed_.find (flip (id)) != unparsed_.end ();
25852636}
25862637
25872638bool Conventions::has (const std::string& id, const Convention::Type& type) const {
@@ -2590,10 +2641,71 @@ bool Conventions::has(const std::string& id, const Convention::Type& type) const
25902641
25912642void Conventions::add (const boost::shared_ptr<Convention>& convention) {
25922643 boost::unique_lock<boost::shared_mutex> lock (mutex_);
2644+ addInternal (convention);
2645+ }
2646+
2647+ void Conventions::addInternal (const boost::shared_ptr<Convention>& convention) const {
25932648 const string& id = convention->id ();
25942649 QL_REQUIRE (data_.find (id) == data_.end (), " Convention already exists for id " << id);
25952650 data_[id] = convention;
25962651}
25972652
2653+ std::ostream& operator <<(std::ostream& out, Convention::Type type) {
2654+ switch (type) {
2655+ case Zero:
2656+ return out << " Zero" ;
2657+ case Deposit:
2658+ return out << " Deposit" ;
2659+ case Future:
2660+ return out << " Future" ;
2661+ case FRA:
2662+ return out << " FRA" ;
2663+ case OIS:
2664+ return out << " OIS" ;
2665+ case Swap:
2666+ return out << " Swap" ;
2667+ case AverageOIS:
2668+ return out << " AverageOIS" ;
2669+ case TenorBasisSwap:
2670+ return out << " TenorBasisSwap" ;
2671+ case TenorBasisTwoSwap:
2672+ return out << " TenorBasisTwoSwap" ;
2673+ case BMABasisSwap:
2674+ return out << " BMABasisSwap" ;
2675+ case FX:
2676+ return out << " FX" ;
2677+ case CrossCcyBasis:
2678+ return out << " CrossCcyBasis" ;
2679+ case CrossCcyFixFloat:
2680+ return out << " CrossCcyFixFloat" ;
2681+ case CDS:
2682+ return out << " CDS" ;
2683+ case IborIndex:
2684+ return out << " IborIndex" ;
2685+ case OvernightIndex:
2686+ return out << " OvernightIndex" ;
2687+ case SwapIndex:
2688+ return out << " SwapIndex" ;
2689+ case ZeroInflationIndex:
2690+ return out << " ZeroInflationIndex" ;
2691+ case InflationSwap:
2692+ return out << " InflationSwap" ;
2693+ case SecuritySpread:
2694+ return out << " SecuritySpread" ;
2695+ case CMSSpreadOption:
2696+ return out << " CMSSpreadOption" ;
2697+ case CommodityForward:
2698+ return out << " CommodityForward" ;
2699+ case CommodityFuture:
2700+ return out << " CommodityFuture" ;
2701+ case FxOption:
2702+ return out << " FxOption" ;
2703+ case BondYield:
2704+ return out << " BondYield" ;
2705+ default :
2706+ return out << " unknown convention type (" << static_cast <int >(type) << " )" ;
2707+ }
2708+ }
2709+
25982710} // namespace data
25992711} // namespace ore
0 commit comments