//! Detailed constructor public FXVolCurve(Date asof, FXVolatilityCurveSpec spec, Loader loader, CurveConfigurations curveConfigs, Dictionary <string, FXSpot> fxSpots, Dictionary <string, YieldCurve> yieldCurves) { try { FXVolatilityCurveConfig config = curveConfigs.FxVolCurveConfig(spec.CurveConfigID()); Utils.QL_REQUIRE(config.GetDimension() == FXVolatilityCurveConfig.Dimension.ATM || config.GetDimension() == FXVolatilityCurveConfig.Dimension.Smile, () => "Unkown FX curve building dimension"); bool isATM = config.GetDimension() == FXVolatilityCurveConfig.Dimension.ATM; // We loop over all market data, looking for quotes that match the configuration // every time we find a matching expiry we remove it from the list // we replicate this for all 3 types of quotes were applicable. int n = isATM ? 1 : 3; // [0] = ATM, [1] = RR, [2] = BF List <List <FXOptionQuote> > quotes = new List <List <FXOptionQuote> >(n); List <List <Period> > expiries = new InitializedList <List <Period> >(n, config.Expiries()); foreach (var md in loader.LoadQuotes(asof)) { // skip irrelevant data if (md.AsofDate() == asof && md.GetInstrumentType() == MarketDatum.InstrumentType.FX_OPTION) { FXOptionQuote q = md as FXOptionQuote; if (q.UnitCcy() == spec.UnitCcy() && q.Ccy() == spec.Ccy()) { int idx = 999999; if (q.Strike() == "ATM") { idx = 0; } else if (q.Strike() == "25RR") { idx = 1; } else if (q.Strike() == "25BF") { idx = 2; } // silently skip unknown strike strings if ((isATM && idx == 0) || (!isATM && idx <= 2)) { if (expiries[idx].Contains(q.Expiry())) //var it = std::find(expiries[idx].begin(), expiries[idx].end(), q->expiry()); //if (it != expiries[idx].end()) { // we have a hit quotes[idx].Add(q); // remove it from the list expiries[idx].Remove(q.Expiry()); } // check if we are done // for ATM we just check expiries[0], otherwise we check all 3 if (expiries[0].empty() && (isATM || (expiries[1].empty() && expiries[2].empty()))) { break; } } } } } // Check ATM first // Check that we have all the expiries we need //LOG("FXVolCurve: read " + quotes[0].Count + " ATM vols"); Utils.QL_REQUIRE(expiries[0].Count == 0, () => "No ATM quote found for spec " + spec + " with expiry " + expiries[0].First()); Utils.QL_REQUIRE(quotes[0].Count > 0, () => "No ATM quotes found for spec " + spec); // No check the rest if (!isATM) { //LOG("FXVolCurve: read " + quotes[1].Count + " RR and " + quotes[2].Count + " BF quotes"); Utils.QL_REQUIRE(expiries[1].Count == 0, () => "No RR quote found for spec " + spec + " with expiry " + expiries[1].First()); Utils.QL_REQUIRE(expiries[2].Count == 0, () => "No BF quote found for spec " + spec + " with expiry " + expiries[2].First()); } // daycounter used for interpolation in time. // TODO: push into conventions or config DayCounter dc = config.DayCounter(); Calendar cal = config.Calendar(); // sort all quotes for (int i = 0; i < n; i++) { // TODO!! //IComparer<FXOptionQuote> compare = //quotes[i] = quotes[i].Sort((a,b) => a.Expiry().CompareTo(b.Expiry())) } // build vol curve if (isATM && quotes[0].Count == 1) { _vol = new BlackConstantVol(asof, new Calendar(), quotes[0].First().Quote().link.value(), dc); } else { int numExpiries = quotes[0].Count; List <Date> dates = new List <Date>(numExpiries); List <List <double> > vols = new InitializedList <List <double> >(n, new List <double>(numExpiries)); // same as above: [0] = ATM, etc. for (int i = 0; i < numExpiries; i++) { dates[i] = asof + quotes[0][i].Expiry(); for (int idx = 0; idx < n; idx++) { vols[idx][i] = quotes[idx][i].Quote().link.value(); } } if (isATM) { // ATM _vol = new BlackVarianceCurve(asof, dates, vols[0], dc, false); } else { // Smile if (fxSpots.ContainsKey(config.FxSpotID()) && yieldCurves.ContainsKey(config.FxDomesticYieldCurveID()) && yieldCurves.ContainsKey(config.FxForeignYieldCurveID())) { var fxSpot = fxSpots[config.FxSpotID()]; // new Handle<Quote>(config.FxSpotID(), fxSpots); var domYTS = yieldCurves[config.FxDomesticYieldCurveID()]; var forYTS = yieldCurves[config.FxForeignYieldCurveID()]; // TODO!! //_vol = new QuantExt.FxBlackVannaVolgaVolatilitySurface(asof, dates, vols[0], vols[1], vols[2], dc, cal, fxSpot, domYTS, forYTS)); } else { Utils.QL_FAIL("FXVolCurve: Can't find spec " + spec); } } } _vol.enableExtrapolation(); } catch (Exception e) { Utils.QL_FAIL("fx vol curve building failed :" + e.Message); } }
public TodaysMarket(Date asof, TodaysMarketParameters todaysParams, Loader loader, CurveConfigurations curveConfigs, Conventions conventions) : base(conventions) { // Fixings // Apply them now in case a curve builder needs them //LOG("Todays Market Loading Fixings"); //applyFixings(loader.loadFixings(), conventions); //LOG("Todays Market Loading Fixing done."); // store all curves built, since they might appear in several configurations // and might therefore be reused Dictionary <string, YieldCurve> requiredYieldCurves = new Dictionary <string, YieldCurve>(); Dictionary <string, SwapIndex> requiredSwapIndices = new Dictionary <string, SwapIndex>(); Dictionary <string, FXSpot> requiredFxSpots = new Dictionary <string, FXSpot>(); Dictionary <string, FXVolCurve> requiredFxVolCurves = new Dictionary <string, FXVolCurve>(); //Dictionary<string, SwaptionVolCurve> requiredSwaptionVolCurves = new Dictionary<string, SwaptionVolCurve>(); foreach (var configuration in todaysParams.Configurations()) { //LOG("Build objects in TodaysMarket configuration " << configuration.first); _asof = asof; // Build the curve specs List <CurveSpec> specs = new List <CurveSpec>(); foreach (var it in todaysParams.CurveSpecs(configuration.Key)) { specs.Add(CurveSpecParser.ParseCurveSpec(it)); //DLOG("CurveSpec: " << specs.back()->name()); } // order them //Order(specs, curveConfigs); bool swapIndicesBuilt = false; // Loop over each spec, build the curve and add it to the MarketImpl container. for (int count = 0; count < specs.Count; ++count) { var spec = specs[count]; //LOG("Loading spec " << *spec); switch (spec.BaseType()) { case CurveSpec.CurveType.Yield: //YieldCurveSpec ycspec = new YieldCurveSpec(spec); //Utils.QL_REQUIRE(ycspec != null, () => "Failed to convert spec " + spec + " to yield curve spec"); //// have we built the curve already ? //auto itr = requiredYieldCurves.find(ycspec->name()); //if (itr == requiredYieldCurves.end()) //{ // // build // //LOG("Building YieldCurve for asof " << asof); // YieldCurve yieldCurve = new YieldCurve(asof, *ycspec, curveConfigs, loader, conventions, requiredYieldCurves); // itr = requiredYieldCurves.insert(make_pair(ycspec->name(), yieldCurve)).first; //} ////DLOG("Added YieldCurve \"" << ycspec->name() << "\" to requiredYieldCurves map"); //if (itr->second->currency().code() != ycspec->ccy()) //{ // //WLOG("Warning: YieldCurve has ccy " << itr->second->currency() << " but spec has ccy " << ycspec->ccy()); //} //// We may have to add this spec multiple times (for discounting, yield and forwarding curves) //List<YieldCurveType> yieldCurveTypes = new List<YieldCurveType>{ YieldCurveType.Discount, YieldCurveType.Yield }; //foreach (var y in yieldCurveTypes) //{ // MarketObject o = y as MarketObject; // foreach (auto & it : params.mapping(o, configuration.first)) // { // if (it.second == spec->name()) // { // LOG("Adding YieldCurve(" << it.first << ") with spec " << *ycspec << " to configuration " << configuration.first); // yieldCurves_[make_tuple(configuration.first, y, it.first)] = itr->second->handle(); // } // } //} //for (const auto&it : params.mapping(MarketObject::IndexCurve, configuration.first)) //{ // if (it.second == spec->name()) // { // LOG("Adding Index(" << it.first << ") with spec " << *ycspec << " to configuration " // << configuration.first); // iborIndices_[make_pair(configuration.first, it.first)] = // Handle<IborIndex>(parseIborIndex(it.first, itr->second->handle())); // } //} break; case CurveSpec.CurveType.FX: FXSpotSpec fxspec = spec as FXSpotSpec; QLNet.Utils.QL_REQUIRE(fxspec != null, () => "Failed to convert spec " + spec + " to fx spot spec"); //// have we built the curve already ? //var itr = requiredFxSpots.find(fxspec->name()); //if (itr == requiredFxSpots.end()) //{ // // build the curve // LOG("Building FXSpot for asof " << asof); // boost::shared_ptr<FXSpot> fxSpot = boost::make_shared<FXSpot>(asof, *fxspec, loader); // itr = requiredFxSpots.insert(make_pair(fxspec->name(), fxSpot)).first; //} //// add the handle to the Market Map (possible lots of times for proxies) //for (const auto&it : params.mapping(MarketObject::FXSpot, configuration.first)) //{ // if (it.second == spec->name()) // { // LOG("Adding FXSpot (" << it.first << ") with spec " << *fxspec << " to configuration " // << configuration.first); // fxSpots_[configuration.first].addQuote(it.first, itr->second->handle()); // } //} break; default: throw new NotImplementedException(); } } } }
/// <summary> /// Constructor /// </summary> /// <param name="asof">Valuation date</param> /// <param name="curveSpec">Yield curve specification</param> /// <param name="curveConfigs">Repository of yield curve configurations</param> /// <param name="loader">Market data loader</param> /// <param name="conventions">Repository of market conventions for building bootstrap helper</param> /// <param name="requiredYieldCurves">Map of underlying yield curves if required</param> public YieldCurve(Date asof, YieldCurveSpec curveSpec, CurveConfigurations curveConfigs, Loader loader, Conventions conventions, Dictionary <string, YieldCurve> requiredYieldCurves = null) { }