public static MarketDatum ParseMarketDatum(Date asof, string datumName, double value) { List <string> tokens = datumName.Split('/').ToList(); Utils.QL_REQUIRE(tokens.Count > 2, () => "more than 2 tokens expected in " + datumName); MarketDatum.InstrumentType instrumentType = ParseInstrumentType(tokens[0]); MarketDatum.QuoteType quoteType = ParseQuoteType(tokens[1]); switch (instrumentType) { case MarketDatum.InstrumentType.ZERO: { //ZERO / RATE / EUR / EUR1D / A365 / 1Y Utils.QL_REQUIRE(quoteType == MarketDatum.QuoteType.RATE || quoteType == MarketDatum.QuoteType.YIELD_SPREAD, () => "Invalid quote type for " + datumName); Utils.QL_REQUIRE(tokens.Count == 6, () => "6 tokens expected in " + datumName); string ccy = tokens[2]; DayCounter dc = Parsers.ParseDayCounter(tokens[4]); // token 5 can be a date, or tenor Date date = new Date(); Period tenor = new Period(); bool isDate = false; Parsers.ParseDateOrPeriod(tokens[5], date, tenor, out isDate); return(new ZeroQuote(value, asof, datumName, quoteType, ccy, date, dc, tenor)); } case MarketDatum.InstrumentType.DISCOUNT: { // DISCOUNT/RATE/EUR/EUR1D/1Y // DISCOUNT/RATE/EUR/EUR1D/2016-12-15 Utils.QL_REQUIRE(tokens.Count == 5, () => "5 tokens expected in " + datumName); string ccy = tokens[2]; // token 4 can be a date, or tenor Date date = new Date(); Period tenor = new Period(); bool isDate = false; Parsers.ParseDateOrPeriod(tokens[4], date, tenor, out isDate); if (!isDate) { // we can't assume any calendar here, so we do the minimal adjustment with a weekend only calendar Utils.QL_REQUIRE(tenor != null, () => "neither date nor tenor recognised"); date = new WeekendsOnly().adjust(asof + tenor); } return(new DiscountQuote(value, asof, datumName, quoteType, ccy, date)); } //case MarketDatum.InstrumentType.MM: // { // QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName); // const string&ccy = tokens[2]; // Period fwdStart = parsePeriod(tokens[3]); // Period term = parsePeriod(tokens[4]); // return boost::make_shared<MoneyMarketQuote>(value, asof, datumName, quoteType, ccy, fwdStart, term); // } //case MarketDatum.InstrumentType.MM_FUTURE: // { // QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName); // const string&ccy = tokens[2]; // const string&expiry = tokens[3]; // const string&contract = tokens[4]; // Period term = parsePeriod(tokens[5]); // return boost::make_shared<MMFutureQuote>(value, asof, datumName, quoteType, ccy, expiry, contract, term); // } case MarketDatum.InstrumentType.FRA: { Utils.QL_REQUIRE(tokens.Count == 5, () => "5 tokens expected in " + datumName); string ccy = tokens[2]; Period fwdStart = Parsers.ParsePeriod(tokens[3]); Period term = Parsers.ParsePeriod(tokens[4]); return(new FRAQuote(value, asof, datumName, quoteType, ccy, fwdStart, term)); } //case MarketDatum.InstrumentType.IMM_FRA: // { // QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName); // const string&ccy = tokens[2]; // string imm1 = tokens[3]; // string imm2 = tokens[4]; // unsigned int m1 = parseInteger(imm1); // unsigned int m2 = parseInteger(imm2); // QL_REQUIRE(m2 > m1, "Second IMM date must be after the first in " << datumName); // return boost::make_shared<ImmFraQuote>(value, asof, datumName, quoteType, ccy, m1, m2); // } case MarketDatum.InstrumentType.IR_SWAP: { Utils.QL_REQUIRE(tokens.Count == 6, () => "6 tokens expected in " + datumName); string ccy = tokens[2]; Period fwdStart = Parsers.ParsePeriod(tokens[3]); Period tenor = Parsers.ParsePeriod(tokens[4]); Period term = Parsers.ParsePeriod(tokens[5]); return(new SwapQuote(value, asof, datumName, quoteType, ccy, fwdStart, term, tenor)); } //case MarketDatum.InstrumentType.BASIS_SWAP: // { // QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName); // Period flatTerm = parsePeriod(tokens[2]); // Period term = parsePeriod(tokens[3]); // const string&ccy = tokens[4]; // Period maturity = parsePeriod(tokens[5]); // return boost::make_shared<BasisSwapQuote>(value, asof, datumName, quoteType, flatTerm, term, ccy, maturity); // } case MarketDatum.InstrumentType.CC_BASIS_SWAP: { Utils.QL_REQUIRE(tokens.Count == 7, () => "7 tokens expected in " + datumName); string flatCcy = tokens[2]; Period flatTerm = Parsers.ParsePeriod(tokens[3]); string ccy = tokens[4]; Period term = Parsers.ParsePeriod(tokens[5]); Period maturity = Parsers.ParsePeriod(tokens[6]); return(new CrossCcyBasisSwapQuote(value, asof, datumName, quoteType, flatCcy, flatTerm, ccy, term, maturity)); } //case MarketDatum.InstrumentType.CDS: // { // QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName); // const string&underlyingName = tokens[2]; // const string&seniority = tokens[3]; // const string&ccy = tokens[4]; // Period term = parsePeriod(tokens[5]); // return boost::make_shared<CdsSpreadQuote>(value, asof, datumName, underlyingName, seniority, ccy, term); // } //case MarketDatum.InstrumentType.HAZARD_RATE: // { // QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName); // const string&underlyingName = tokens[2]; // const string&seniority = tokens[3]; // const string&ccy = tokens[4]; // Period term = parsePeriod(tokens[5]); // return boost::make_shared<HazardRateQuote>(value, asof, datumName, underlyingName, seniority, ccy, term); // } //case MarketDatum.InstrumentType.RECOVERY_RATE: // { // QL_REQUIRE(tokens.size() == 3 || tokens.size() == 5, "3 or 5 tokens expected in " << datumName); // const string&underlyingName = tokens[2]; // issuer name for CDS, security ID for bond specific RRs // string seniority = ""; // string ccy = ""; // if (tokens.size() == 5) // { // // CDS // seniority = tokens[3]; // ccy = tokens[4]; // } // return boost::make_shared<RecoveryRateQuote>(value, asof, datumName, underlyingName, seniority, ccy); // } //case MarketDatum.InstrumentType.CAPFLOOR: // { // QL_REQUIRE(tokens.size() == 8 || tokens.size() == 4, "Either 4 or 8 tokens expected in " << datumName); // const string&ccy = tokens[2]; // if (tokens.size() == 8) // { // Period term = parsePeriod(tokens[3]); // Period tenor = parsePeriod(tokens[4]); // bool atm = parseBool(tokens[5].c_str()); // bool relative = parseBool(tokens[6].c_str()); // Real strike = parseReal(tokens[7]); // return boost::make_shared<CapFloorQuote>(value, asof, datumName, quoteType, ccy, term, tenor, atm, relative, // strike); // } // else // { // Period indexTenor = parsePeriod(tokens[3]); // return boost::make_shared<CapFloorShiftQuote>(value, asof, datumName, quoteType, ccy, indexTenor); // } // } case MarketDatum.InstrumentType.SWAPTION: { Utils.QL_REQUIRE(tokens.Count == 4 || tokens.Count == 6 || tokens.Count == 7, () => "4, 6 or 7 tokens expected in " + datumName); string ccy = tokens[2]; Period expiry = tokens.Count >= 6 ? Parsers.ParsePeriod(tokens[3]) : new Period(0, TimeUnit.Days); Period term = tokens.Count >= 6 ? Parsers.ParsePeriod(tokens[4]) : Parsers.ParsePeriod(tokens[3]); if (tokens.Count >= 6) { // volatility string dimension = tokens[5]; double strike = 0.0; if (dimension == "ATM") { Utils.QL_REQUIRE(tokens.Count == 6, () => "6 tokens expected in ATM quote " + datumName); } else if (dimension == "Smile") { Utils.QL_REQUIRE(tokens.Count == 7, () => "7 tokens expected in Smile quote " + datumName); strike = Parsers.ParseDouble(tokens[6]); } else { Utils.QL_FAIL("Swaption vol quote dimension " + dimension + " not recognised"); } return(new SwaptionQuote(value, asof, datumName, quoteType, ccy, expiry, term, dimension, strike)); } else { // SLN volatility shift return(null); //return new SwaptionShiftQuote(value, asof, datumName, quoteType, ccy, term); } } case MarketDatum.InstrumentType.FX_SPOT: { Utils.QL_REQUIRE(tokens.Count == 4, () => "4 tokens expected in " + datumName); string unitCcy = tokens[2]; string ccy = tokens[3]; return(new FXSpotQuote(value, asof, datumName, quoteType, unitCcy, ccy)); } case MarketDatum.InstrumentType.FX_FWD: { Utils.QL_REQUIRE(tokens.Count == 5, () => "5 tokens expected in " + datumName); string unitCcy = tokens[2]; string ccy = tokens[3]; Period term = Parsers.ParsePeriod(tokens[4]); return(new FXForwardQuote(value, asof, datumName, quoteType, unitCcy, ccy, term)); } case MarketDatum.InstrumentType.FX_OPTION: { Utils.QL_REQUIRE(tokens.Count == 6, () => "6 tokens expected in " + datumName); string unitCcy = tokens[2]; string ccy = tokens[3]; Period expiry = Parsers.ParsePeriod(tokens[4]); string strike = tokens[5]; return(new FXOptionQuote(value, asof, datumName, quoteType, unitCcy, ccy, expiry, strike)); } //case MarketDatum.InstrumentType.ZC_INFLATIONSWAP: // { // QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName); // const string&index = tokens[2]; // Period term = parsePeriod(tokens[3]); // return boost::make_shared<ZcInflationSwapQuote>(value, asof, datumName, index, term); // } //case MarketDatum.InstrumentType.YY_INFLATIONSWAP: // { // QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName); // const string&index = tokens[2]; // Period term = parsePeriod(tokens[3]); // return boost::make_shared<YoYInflationSwapQuote>(value, asof, datumName, index, term); // } //case MarketDatum.InstrumentType.ZC_INFLATIONCAPFLOOR: // { // QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName); // const string&index = tokens[2]; // Period term = parsePeriod(tokens[3]); // QL_REQUIRE(tokens[4] == "C" || tokens[4] == "F", // "excepted C or F for Cap or Floor at position 5 in " << datumName); // bool isCap = tokens[4] == "C"; // string strike = tokens[5]; // return boost::make_shared<ZcInflationCapFloorQuote>(value, asof, datumName, quoteType, index, term, isCap, // strike); // } //case MarketDatum.InstrumentType.SEASONALITY: // { // QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName); // const string&index = tokens[3]; // const string&type = tokens[2]; // const string&month = tokens[4]; // return boost::make_shared<SeasonalityQuote>(value, asof, datumName, index, type, month); // } //case MarketDatum.InstrumentType.EQUITY_SPOT: // { // QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName); // QL_REQUIRE(quoteType == MarketDatum.QuoteType.PRICE, "Invalid quote type for " << datumName); // const string&equityName = tokens[2]; // const string&ccy = tokens[3]; // return boost::make_shared<EquitySpotQuote>(value, asof, datumName, quoteType, equityName, ccy); // } //case MarketDatum.InstrumentType.EQUITY_FWD: // { // QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName); // QL_REQUIRE(quoteType == MarketDatum.QuoteType.PRICE, "Invalid quote type for " << datumName); // const string&equityName = tokens[2]; // const string&ccy = tokens[3]; // Date expiryDate = getDateFromDateOrPeriod(tokens[4], asof); // return boost::make_shared<EquityForwardQuote>(value, asof, datumName, quoteType, equityName, ccy, expiryDate); // } //case MarketDatum.InstrumentType.EQUITY_DIVIDEND: // { // QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName); // QL_REQUIRE(quoteType == MarketDatum.QuoteType.RATE, "Invalid quote type for " << datumName); // const string&equityName = tokens[2]; // const string&ccy = tokens[3]; // Date tenorDate = getDateFromDateOrPeriod(tokens[4], asof); // return boost::make_shared<EquityDividendYieldQuote>(value, asof, datumName, quoteType, equityName, ccy, // tenorDate); // } //case MarketDatum.InstrumentType.EQUITY_OPTION: // { // QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName); // QL_REQUIRE(quoteType == MarketDatum.QuoteType.RATE_LNVOL, "Invalid quote type for " << datumName); // const string&equityName = tokens[2]; // const string&ccy = tokens[3]; // string expiryString = tokens[4]; // const string&strike = tokens[5]; // // note how we only store the expiry string - to ensure we can support both Periods and Dates being specified in // // the vol curve-config. // return boost::make_shared<EquityOptionQuote>(value, asof, datumName, quoteType, equityName, ccy, expiryString, // strike); // } //case MarketDatum.InstrumentType.BOND: // { // QL_REQUIRE(tokens.size() == 3, "3 tokens expected in " << datumName); // const string&securityID = tokens[2]; // return boost::make_shared<SecuritySpreadQuote>(value, asof, datumName, securityID); // } //case MarketDatum.InstrumentType.CDS_INDEX: // { // QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName); // QL_REQUIRE(quoteType == MarketDatum.QuoteType.BASE_CORRELATION, "Invalid quote type for " << datumName); // const string&cdsIndexName = tokens[2]; // Period term = parsePeriod(tokens[3]); // Real detachmentPoint = parseReal(tokens[4]); // return boost::make_shared<BaseCorrelationQuote>(value, asof, datumName, quoteType, cdsIndexName, term, // detachmentPoint); // } //case MarketDatum.InstrumentType.INDEX_CDS_OPTION: // { // QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName); // QL_REQUIRE(quoteType == MarketDatum.QuoteType.RATE_LNVOL, "Invalid quote type for " << datumName); // const string&indexName = tokens[2]; // const string&expiry = tokens[3]; // return boost::make_shared<IndexCDSOptionQuote>(value, asof, datumName, indexName, expiry); // } default: //Utils.QL_FAIL("Cannot convert \"" + datumName + "\" to MarketDatum"); return(null); } }