// Build with: // emcc --bind -I${EMSCRIPTEN}/system/include -I${QUANTLIB} -I${BOOST} -O3 -s // MODULARIZE=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['addOnPostRun']" -s // EXPORT_NAME=QuantLib -s TOTAL_MEMORY=64MB -o quantlib-embind.js // quantlib-embind.cpp ${QUANTLIB}/ql/.libs/libQuantLib.a // https://www.quantlib.org/slides/dima-ql-intro-1.pdf #include #include #include #include #include #include using namespace std; using namespace QuantLib; using namespace emscripten; namespace { val emval_test_mallinfo() { const auto &i = mallinfo(); unsigned long t = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1); val rv(val::object()); rv.set("arena", val(i.arena)); rv.set("ordblks", val(i.ordblks)); rv.set("smblks", val(i.smblks)); rv.set("hblks", val(i.hblks)); rv.set("hblkhd", val(i.hblkhd)); rv.set("usmblks", val(i.usmblks)); rv.set("fsmblks", val(i.fsmblks)); rv.set("uordblks", val(i.uordblks)); rv.set("fordblks", val(i.fordblks)); rv.set("keepcost", val(i.keepcost)); rv.set("time", val(t)); return rv; } void setValuationDate(Date &date) { Settings::instance().evaluationDate() = date; } string timeUnitToString(Period &p) { stringstream stream; stream << p; return stream.str(); } double swapNpv(VanillaSwap &swap) { return swap.NPV(); } string calendarToISOString(Date &d) { stringstream stream; stream << d.year() << "-" << setfill('0') << setw(2) << (int)d.month() << "-" << setfill('0') << setw(2) << d.dayOfMonth(); return stream.str(); } string calendarToString(Date &d) { stringstream stream; stream << d; return stream.str(); } string interestRateToString(InterestRate &r) { stringstream stream; stream.precision(4); stream << r; return stream.str(); } Date calendarAdvance(Calendar &cal, Date &d, Integer n, TimeUnit unit, BusinessDayConvention c, bool endOfMonth) { return cal.advance(d, n, unit, c, endOfMonth); } Date *dateFromISOString(string s) { int y, m, d; sscanf(s.c_str(), "%d-%d-%d", &y, &m, &d); return new Date(d, (Month)m, y); } void swapSetPricingEngine( VanillaSwap &swap, Handle &discountingTermStructure) { boost::shared_ptr swapEngine( new DiscountingSwapEngine(discountingTermStructure)); swap.setPricingEngine(swapEngine); } Handle * createLogLinearYieldTermStructure(vector &dates, vector &discountFactor, DayCounter &dayCounter) { // auto curve = new InterpolatedDiscountCurve(dates, // discountFactor, dayCounter); InterpolatedDiscountCurve // curve(InterpolatedDiscountCurve(dates, discountFactor, // dayCounter)); auto yts = // boost::make_shared>(*curve); boost::shared_ptr yts( new InterpolatedDiscountCurve(dates, discountFactor, dayCounter)); return new Handle(yts); } VanillaSwap *createVanillaSwap(VanillaSwap::Type type, Real nominal, const Schedule &fixedSchedule, Rate fixedRate, DayCounter &fixedDayCount, const Schedule &floatSchedule, IborIndex &iborIndex, Spread spread, DayCounter &floatingDayCount) { boost::shared_ptr iborIndexPtr = boost::make_shared(iborIndex); VanillaSwap *res = new VanillaSwap(type, nominal, fixedSchedule, fixedRate, fixedDayCount, floatSchedule, iborIndexPtr, spread, floatingDayCount); return res; } Handle *createQuoteHandle(Rate rate) { boost::shared_ptr ptrSimpleQuote = boost::make_shared(rate); boost::shared_ptr ptrQuote(ptrSimpleQuote); return new Handle(ptrQuote); } Real handleQuoteValue(Handle "e) { return ((ext::shared_ptr &)quote.currentLink())->value(); } OISRateHelper *createOISRateHelper( Natural settlementDays, Period &tenor, Handle &fixedRate, OvernightIndex &overnightIndex /*, Handle &discountingCurve, bool telescopicValueDates, Natural paymentLag, BusinessDayConvention paymentConvention, Frequency paymentFrequency, Calendar &paymentCalendar, Period &forwardStart, Spread overnightSpread */ ) { ext::shared_ptr ptrOvernightIndex(&overnightIndex); return new OISRateHelper(settlementDays, tenor, fixedRate, ptrOvernightIndex /*, discountingCurve, telescopicValueDates, paymentLag, paymentConvention, paymentFrequency, paymentCalendar, forwardStart, overnightSpread*/ ); } DatedOISRateHelper *createDatedOISRateHelper(Date &startDate, Date &endDate, Handle &fixedRate, OvernightIndex &overnightIndex) { ext::shared_ptr ptrOvernightIndex(&overnightIndex); return new DatedOISRateHelper(startDate, endDate, fixedRate, ptrOvernightIndex); } FuturesRateHelper * createFuturesRateHelper(Handle &price, Date &iborStartDate, Natural lengthInMonths, Calendar &calendar, BusinessDayConvention convention, bool endOfMonth, DayCounter &dayCounter) { return new FuturesRateHelper(price, iborStartDate, lengthInMonths, calendar, convention, endOfMonth, dayCounter); } SwapRateHelper *createSwapRateHelper(Handle &rate, Period &tenor, Calendar &calendar, Frequency fixedFrequency, BusinessDayConvention fixedConvention, DayCounter &fixedDayCount, IborIndex &iborIndex) { boost::shared_ptr ptrIborIndex = boost::make_shared(iborIndex); // ext::shared_ptr ptrIborIndex(&iborIndex); return new SwapRateHelper(rate, tenor, calendar, fixedFrequency, fixedConvention, fixedDayCount, ptrIborIndex); } Date *immNextDate(const Date &date, bool mainCycle) { return new Date(IMM::nextDate(date, mainCycle).serialNumber()); } PiecewiseYieldCurve * createPiecewiseYieldCurveDiscountLinear(Date &referenceDate, vector &instruments, DayCounter &dayCounter) { vector> ptrs; for (int i = 0; i < instruments.size(); i++) { // boost::shared_ptr ptr = // boost::make_shared(instruments[i]); // ext::shared_ptr ptr(&instruments[i]); boost::shared_ptr ptr(instruments[i]); ptrs.push_back(ptr); } return new PiecewiseYieldCurve(referenceDate, ptrs, dayCounter); } void handle_eptr(std::exception_ptr eptr) // passing by value is ok { try { if (eptr) { std::rethrow_exception(eptr); } } catch (const std::exception &e) { std::cout << "Caught exception \"" << e.what() << "\"\n"; } } InterestRate *yieldTermStructureZeroRate(YieldTermStructure &yieldTermStructure, Date &d, DayCounter &resultDayCounter, Compounding comp, Frequency freq, bool extrapolate) { // try // { // std::cout << "Uno" << std::endl; // auto dates = yieldTermStructure.jumpDates(); // std::cout << "Due" << std::endl; // for (int i=0; iwhat() << std::endl; // } // return NULL; } DiscountFactor yieldTermStructureDiscount(YieldTermStructure &yieldTermStructure, Date &d, bool extrapolate) { return yieldTermStructure.discount(d, extrapolate); } InterestRate * yieldTermStructureForwardRate(YieldTermStructure &yieldTermStructure, Date &d1, Date &d2, DayCounter &resultDayCounter, Compounding comp, Frequency freq, bool extrapolate) { auto r = yieldTermStructure.forwardRate(d1, d2, resultDayCounter, comp, freq, extrapolate); return new InterestRate(r.rate(), r.dayCounter(), r.compounding(), r.frequency()); // Copies from stack to heap memory } EMSCRIPTEN_BINDINGS(quantlib) { emscripten::constant("version", QL_VERSION); enum_("BusinessDayConvention") .value("Following", Following) .value("ModifiedFollowing", ModifiedFollowing) .value("Preceding", Preceding) .value("ModifiedPreceding", ModifiedPreceding) .value("Unadjusted", Unadjusted) .value("HalfMonthModifiedFollowing", HalfMonthModifiedFollowing) .value("Nearest", Nearest); enum_("Month") .value("January", January) .value("February", February) .value("March", March) .value("April", April) .value("May", May) .value("June", June) .value("July", July) .value("August", August) .value("September", September) .value("October", October) .value("November", November) .value("December", December) .value("Jan", Jan) .value("Feb", Feb) .value("Mar", Mar) .value("Apr", Apr) .value("May", May) .value("Jun", Jun) .value("Jul", Jul) .value("Aug", Aug) .value("Sep", Sep) .value("October", Oct) .value("Nov", Nov) .value("Dec", Dec); enum_("TimeUnit") .value("D", Days) .value("W", Weeks) .value("M", Months) .value("Y", Years) .value("Days", Days) .value("Weeks", Weeks) .value("Months", Months) .value("Years", Years) .value("Hours", Hours) .value("Minutes", Minutes) .value("Seconds", Seconds) .value("Milliseconds", Milliseconds) .value("Microseconds", Microseconds); enum_("DateGenerationRule") .value("Backward", DateGeneration::Backward) .value("Forward", DateGeneration::Forward) .value("Zero", DateGeneration::Zero) .value("ThirdWednesday", DateGeneration::ThirdWednesday) .value("Twentieth", DateGeneration::Twentieth) .value("TwentiethIMM", DateGeneration::TwentiethIMM) .value("OldCDS", DateGeneration::OldCDS) .value("CDS", DateGeneration::CDS) .value("CDS2015", DateGeneration::CDS2015); enum_("Thirty360Convention") .value("USA", Thirty360::USA) .value("BondBasis", Thirty360::BondBasis) .value("European", Thirty360::European) .value("EurobondBasis", Thirty360::EurobondBasis) .value("Italian", Thirty360::Italian) .value("German", Thirty360::German); enum_("ActualActualConvention") .value("ISMA", ActualActual::ISMA) .value("Bond", ActualActual::Bond) .value("ISDA", ActualActual::ISDA) .value("Historical", ActualActual::Historical) .value("Actual365", ActualActual::Actual365) .value("AFB", ActualActual::AFB) .value("Euro", ActualActual::Euro); enum_("VanillaSwapType") .value("Payer", VanillaSwap::Payer) .value("Receiver", VanillaSwap::Receiver); enum_("Weekday") .value("Sunday", Sunday) .value("Monday", Monday) .value("Tuesday", Tuesday) .value("Wednesday", Wednesday) .value("Thursday", Thursday) .value("Friday", Friday) .value("Saturday", Saturday) .value("Sun", Sun) .value("Mon", Mon) .value("Tue", Tue) .value("Wed", Wed) .value("Thu", Thu) .value("Fri", Fri) .value("Sat", Sat); enum_("PillarChoice") .value("MaturityDate", Pillar::Choice::MaturityDate) .value("LastRelevantDate", Pillar::Choice::LastRelevantDate) .value("CustomDate", Pillar::Choice::CustomDate); enum_("UnitedStatesMarket") .value("Settlement", UnitedStates::Market::Settlement) .value("NYSE", UnitedStates::Market::NYSE) .value("GovernmentBond", UnitedStates::Market::GovernmentBond) .value("NERC", UnitedStates::Market::NERC) .value("LiborImpact", UnitedStates::Market::LiborImpact) .value("FederalReserve", UnitedStates::Market::FederalReserve); enum_("UnitedKingdomMarket") .value("Settlement", UnitedKingdom::Market::Settlement) .value("Exchange", UnitedKingdom::Market::Exchange) .value("Metals", UnitedKingdom::Market::Metals); enum_("JointCalendarRule") .value("JoinHolidays", JointCalendarRule::JoinHolidays) .value("JoinBusinessDays", JointCalendarRule::JoinBusinessDays); enum_("Frequency") .value("NoFrequency", NoFrequency) .value("Once", Once) .value("Annual", Annual) .value("Semiannual", Semiannual) .value("EveryFourthMonth", EveryFourthMonth) .value("Quarterly", Quarterly) .value("Bimonthly", Bimonthly) .value("Monthly", Monthly) .value("EveryFourthWeek", EveryFourthWeek) .value("Biweekly", Biweekly) .value("Weekly", Weekly) .value("Daily", Daily) .value("OtherFrequency", OtherFrequency); enum_("Compounding") .value("Simple", Simple) .value("Compounded", Compounded) .value("Continuous", Continuous) .value("SimpleThenCompounded", SimpleThenCompounded) .value("CompoundedThenSimple", CompoundedThenSimple); register_vector("Vector").constructor(); register_vector("Vector").constructor(); register_vector("Vector").constructor(); register_vector("Vector").constructor(); class_("Date") .constructor<>() .constructor() .constructor() .function("serialNumber", &Date::serialNumber) .function("weekday", &Date::weekday) .function("dayOfMonth", &Date::dayOfMonth) .function("dayOfYear", &Date::dayOfYear) .function("month", &Date::month) .function("year", &Date::year) .function("toISOString", &calendarToISOString) .function("toString", &calendarToString) .class_function("fromISOString", &dateFromISOString, allow_raw_pointers()) .class_function("isLeap", &Date::isLeap); class_("Schedule") .constructor>() .constructor() .function("size", &Schedule::size) .function("dates", &Schedule::dates); /* Calendars */ class_("Calendar") .function("name", &Calendar::name) .function("toString", &calendarToString) .function("isBusinessDay", &Calendar::isBusinessDay) .function("adjust", &Calendar::adjust) // .function("advance", // &Calendar::advance) .function("advance", &calendarAdvance); class_>("JointCalendar") .constructor() .constructor() .constructor(); class_>("TARGET").constructor<>(); class_>("NullCalendar").constructor<>(); class_>("UnitedKingdom") .constructor(); class_>("UnitedStates") .constructor(); class_>("Sweden").constructor<>(); /* Period */ class_("Period").constructor().function( "toString", &timeUnitToString); /* DayCounters */ class_("DayCounter") .function("name", &DayCounter::name) .function("dayCount", &DayCounter::dayCount) .function("yearFraction", &DayCounter::yearFraction); class_>("Thirty360") .constructor(); class_>("Actual360") .constructor<>() .constructor(); class_>("Actual365Fixed").constructor<>(); class_>("ActualActual") .constructor(); class_>("Business252").constructor<>(); class_>( "OptionalBusinessDayConvention"); /* Misc */ class_("VanillaSwap") .constructor(&createVanillaSwap, allow_raw_pointers()) // .constructor, Spread, DayCounter, // boost::optional>() .class_function("create", &createVanillaSwap, allow_raw_pointers()) .function("setPricingEngine", &swapSetPricingEngine) .function("NPV", &swapNpv); class_>("Handle"); emscripten::function("createVanillaSwap", &createVanillaSwap, allow_raw_pointers()); emscripten::function("mallinfo", &emval_test_mallinfo); emscripten::function("setValuationDate", &setValuationDate); emscripten::function("createLogLinearYieldTermStructure", &createLogLinearYieldTermStructure, allow_raw_pointers()); class_("InterestRate") .function("rate", &InterestRate::rate) .function("toString", &interestRateToString); class_("Quote"); class_>("SimpleQuote").constructor(); class_>("QuoteHandle") .constructor(&createQuoteHandle, allow_raw_pointers()) .function("value", &handleQuoteValue); class_("IMM").class_function("nextDate", &immNextDate, allow_raw_pointers()); /* Indicies */ class_("Index").function("addFixing", &Index::addFixing); class_>("InterestRateIndex") .function("fixingDate", &InterestRateIndex::fixingDate); class_>("IborIndex"); class_>("Euribor") .constructor>(); class_>("OvernightIndex"); class_>("Eonia").constructor(); class_>("Libor"); class_>("USDLibor") .constructor() .constructor>(); /* Helpers */ class_("RateHelper") .function("maturityDate", &RateHelper::maturityDate) .function("quote", &RateHelper::quote); class_>("DepositRateHelper") .constructor, Period, Natural, Calendar, BusinessDayConvention, bool, DayCounter>(); class_>("OISRateHelper") .constructor(&createOISRateHelper, allow_raw_pointers()); class_>("DatedOISRateHelper") .constructor(&createDatedOISRateHelper, allow_raw_pointers()); class_>("FuturesRateHelper") .constructor(&createFuturesRateHelper, allow_raw_pointers()); class_>("SwapRateHelper") .constructor(&createSwapRateHelper, allow_raw_pointers()); class_("ZeroInflationTermStructure") .function("zeroRate", &yieldTermStructureZeroRate, allow_raw_pointers()) .function("discount", &yieldTermStructureDiscount) .function("forwardRate", &yieldTermStructureForwardRate, allow_raw_pointers()); class_, base>( "PiecewiseYieldCurve") .constructor(&createPiecewiseYieldCurveDiscountLinear, allow_raw_pointers()); } } // namespace // In [9]: eonia_curve_c = PiecewiseLogCubicDiscount(0, TARGET(), // helpers, Actual365Fixed()) // eonia_curve_c.enableExtrapolation()