The QuantLib C++ library

QuantLib: the free/open-source library for quantitative finance

Download Licensed under the BSD 3-Clause License DOI PRs Welcome

Linux build status Windows build status Mac OS build status CMake build status

Codacy Badge Code Quality: Cpp Coverage Status


The QuantLib project (http://quantlib.org) is aimed at providing a comprehensive software framework for quantitative finance. QuantLib is a free/open-source library for modeling, trading, and risk management in real-life.

QuantLib is Non-Copylefted Free Software and OSI Certified Open Source Software.

Download and usage

QuantLib can be downloaded from http://quantlib.org/download.shtml; installation instructions are available at http://quantlib.org/install.shtml for most platforms.

Documentation for the usage and the design of the QuantLib library is available from http://quantlib.org/docs.shtml.

A list of changes for each past versions of the library can be browsed at http://quantlib.org/reference/history.html.

Questions and feedback

The preferred channel for questions (and the one with the largest audience) is the quantlib-users mailing list. Instructions for subscribing are at http://quantlib.org/mailinglists.shtml.

Bugs can be reported as a GitHub issue at https://github.com/lballabio/QuantLib/issues; if you have a patch available, you can open a pull request instead (see "Contributing" below).

Contributing

The preferred way to contribute is through pull requests on GitHub. Get a GitHub account if you don't have it already and clone the repository at https://github.com/lballabio/QuantLib with the "Fork" button in the top right corner of the page. Check out your clone to your machine, code away, push your changes to your clone and submit a pull request; instructions are available at https://help.github.com/articles/fork-a-repo.

In case you need them, more detailed instructions for creating pull requests are at https://help.github.com/articles/using-pull-requests, and a basic guide to GitHub is at https://guides.github.com/activities/hello-world/. GitHub also provides interactive learning at https://lab.github.com/.

It's likely that we won't merge your code right away, and we'll ask for some changes instead. Don't be discouraged! That's normal; the library is complex, and thus it might take some time to become familiar with it and to use it in an idiomatic way.

We're looking forward to your contributions.

Owner
Luigi Ballabio
One of the administrators and lead developers of the QuantLib project. Also husband, father of four, ex-physicist, and amateur musician.
Luigi Ballabio
Comments
  • Callable Bond Pricing Issue

    Callable Bond Pricing Issue

    Hi,

    I am a big fan of Quantlib and I have been using quantlib python to price thousands of callable bonds every day (from OAS to clean price and from price to OAS). I am still learning the library as I am not so familiar with C++ and online resources on python examples are somewhat limited, so I have to explore a lot of things myself.

    Now, I have an issue with callable bond pricing. I am trying to compute the clean price of a real callable bond in the credit market, namely AES 6 05/15/26. I set the coupon rate to 10% instead of original 6% just to let you see the problem clearly on a larger scale.

    This bond is near the call date (next call is on 5/15/21, in roughly 0.5 years, and the call price is 103) so if the spread is near 0 and the valuation date is today (11/3/2020), I would expect the bond to be priced around 108 as it is "priced to next call". This is also confirmed by Bloomberg. However as I shocked the OAS of the bond to 1bp, the price I got was actually 113.27, well above that. What happens I guess is that the quantlib is mistakenly pricing in one more coupon payment (there is only half a year left so only 1 semi-annual coupon before the call).

    To replicate the bug in an even more straightforward way, I change the next call date to 11/10/2020, which is just 7 days from now, and the "clean price" I got based on 1bp of OAS is 108.19, still well above 103, which is the call price I had expected (again, it looks like one more coupon is priced in).

    Magically, If I set the next call date to 11/9/2020, the price is finally consistent with my intuition, at 103.17, meaning by just changing the call date from 11/10/2020 to 11/9/2020, the clean price dropped 5pts! This strange behavior made me wonder if the cleanPriceOAS function is in fact computing the dirty price or something else.

    I have posted my code below (you can run it directly). Could you please take a look and let me know if I am using the pricer in a correct way or there is actually a bug somewhere? Any hint or suggestion are highly appreciated here!

    import numpy as np
    import pandas as pd
    import QuantLib as ql
    from datetime import datetime, timedelta
    
    today = datetime.today()
    dayCount = ql.Thirty360()
    calendar = ql.UnitedStates()
    interpolation = ql.Linear()
    compounding = ql.Compounded
    compoundingFrequency = ql.Semiannual
    tenor = ql.Period(ql.Semiannual)
    bussinessConvention = ql.Unadjusted
    dateGeneration = ql.DateGeneration.Backward
    monthEnd = False
    
    class CallableBond(object):        
        #a wrapper I define to hold ql objects.
        def __init__(self, issue_dt = None, maturity_dt = None, coupon = None, calldates = [], callprices = []):
            self.issue_dt = issue_dt
            self.maturity_dt = maturity_dt
            self.callprices = callprices
            self.calldates = calldates
            self.coupon = coupon
            self.today_dt = today
            self.callability_schedule = ql.CallabilitySchedule()
            for i, call_dt in enumerate(self.calldates):
                callpx = self.callprices[i]
                day, month, year = call_dt.day, call_dt.month, call_dt.year
                call_date = ql.Date(day, month, year)
                callability_price  = ql.CallabilityPrice(callpx, ql.CallabilityPrice.Clean)
                self.callability_schedule.append(ql.Callability(
                                        callability_price,
                                        ql.Callability.Call,
                                        call_date))
    
        def value_bond(self, a, s, grid_points):
            model = ql.HullWhite(self.spotCurveHandle, a, s)
            engine = ql.TreeCallableFixedRateBondEngine(model, grid_points, self.spotCurveHandle)
            self.model = model
            self.bond.setPricingEngine(engine)
            return self.bond
    
        def makebond(self, asofdate = today):
            self.maturityDate = ql.Date(self.maturity_dt.day, self.maturity_dt.month, self.maturity_dt.year)
            self.dayCount = dayCount
            self.calendar = calendar
            self.interpolation = interpolation
            self.compounding = compounding
            self.compoundingFrequency = compoundingFrequency
    
    
            AsofDate = ql.Date(asofdate.day, asofdate.month, asofdate.year)
            ql.Settings.instance().evaluationDate = AsofDate
            self.asofdate = asofdate
            self.spotRates = list(np.array([0.0811, 0.0811, 0.0864, 0.0938, 0.1167, 0.1545, 0.1941, 0.3749, 0.6235, 0.8434, 1.3858, 1.6163, 1.6163])/100)
            self.spotDates = [ql.Date(3,11,2020), ql.Date(3,12,2020), ql.Date(1,2,2021), ql.Date(30,4,2021), ql.Date(3,11,2021), ql.Date(4,11,2022), ql.Date(3,11,2023), ql.Date(3,11,2025), ql.Date(4,11,2027), ql.Date(4,11,2030), ql.Date(2,11,2040), ql.Date(4,11,2050), ql.Date(3,11,2090)]
            spotCurve_asofdate = ql.ZeroCurve(self.spotDates, self.spotRates, self.dayCount, self.calendar, self.interpolation, self.compounding, self.compoundingFrequency)
            spotCurveHandle1 = ql.YieldTermStructureHandle(spotCurve_asofdate)
            self.spotCurve = spotCurve_asofdate
            self.spotCurveHandle = spotCurveHandle1
    
            self.issueDate = ql.Date(self.issue_dt.day, self.issue_dt.month, self.issue_dt.year)
            self.tenor = tenor
            self.bussinessConvention = bussinessConvention
            self.schedule = ql.Schedule(self.issueDate, self.maturityDate, self.tenor, self.calendar, self.bussinessConvention, self.bussinessConvention , dateGeneration, monthEnd)
            self.coupons = [self.coupon]
            self.settlementDays = 0
            self.faceValue = 100
            self.bond = ql.CallableFixedRateBond(
                self.settlementDays, self.faceValue,
                self.schedule, self.coupons, self.dayCount,
                ql.Following, self.faceValue, self.issueDate,
                self.callability_schedule)
            self.value_bond(0.03, 0.012, 80)
    
        def cleanPriceOAS(self, oas = None):
            if np.isnan(oas):
                return np.nan
            px = self.bond.cleanPriceOAS(oas, self.spotCurveHandle, self.dayCount, self.compounding, self.compoundingFrequency, self.spotCurveHandle.referenceDate())
            return px
    
    if __name__ == '__main__':
        issue_dt = datetime(2016, 5, 25)
        maturity_dt = datetime(2026, 5, 15)
        coupon = 10/100
        calldates, callprices = [datetime(2020, 11, 9), datetime(2022, 5, 15), datetime(2023, 5, 15), datetime(2024, 5, 15)], [103, 102, 101, 100]
        bond = CallableBond(issue_dt, maturity_dt, coupon, calldates, callprices)
        bond.makebond(datetime.today())
        print(bond.cleanPriceOAS(1/10000))   #computing the clean price for OAS=1bp, with call date 11/9/2020 would give 103.17
    
  • 'static void IborCoupon::createIndexedCoupons();' instead of QL_USE_INDEXED_COUPON

    'static void IborCoupon::createIndexedCoupons();' instead of QL_USE_INDEXED_COUPON

    Hi all,

    I see some discussions around the preprocessor flag QL_USE_INDEXED_COUPON.

    One of the main disadvantages is the compile-time nature of this flag. In my opinion the results of calculation should not depend on preprocessor but should be configurable at run-time.

    I suggest to extend the Settings class and use Settings::instance().useIndexedCoupon() to switch programmatically between par and indexed coupons.

    I adjusted all code lines which link to QL_USE_INDEXED_COUPON to use Settings::instance().useIndexedCoupon() instead.

    What do you think of the changes?

    Best regards, Ralf

  • Resolves Issue 518

    Resolves Issue 518

    I believe that this pull request resolves all outstanding issues with the ActualActual ISMA implelmentation described in issue 518.

    The only remaining failing tests are regression tests. Differences are to be expected due to the fact that these were previously incorrect.

    Further tests that should be added:

    1. bondPrices cacluated from the pricing engine should now be consistent with prices from the bondYield(cleanPrice ....) functions for Actual Actual bonds. A test should be created to make sure that this si always true.
    2. Explicit tests of a bond accrual tested against known good values to make sure that when using a schedule all the values feed through correctly to bond accrual valuations.
    3. We must resolve the broken regression tests. I suspect this means that they may have been wrong before when using the actual actual without a schedule.

    Phil

  • Missing config.hpp after make install using CMake-based build

    Missing config.hpp after make install using CMake-based build

    Hi QuantLib-devs,

    thanks for a very useful library. I'm having a slightly strange problem, no doubt related to how I am building the library - but I'm afraid I can't quite figure out what I am doing wrong. I am trying to build an alpine container with a set of C++ libraries including QuantLib and OpenSourceRiskEngine (OSRE) [1].

    Possibly quite important: I am using CMake for building QuantLib.

    At any rate, I get QuantLib to build and install just fine - can't spot anything untoward in the build output - but when I look at the install directory, it is missing ql/config.hpp:

    $  ls -l /usr/include/ql/config*
    -rw-r--r--    1 root     root           957 Jan 23 13:55 /usr/include/ql/config.ansi.hpp
    -rw-r--r--    1 root     root           963 Jan 23 13:55 /usr/include/ql/config.mingw.hpp
    -rw-r--r--    1 root     root          2664 Jan 23 13:55 /usr/include/ql/config.msvc.hpp
    -rw-r--r--    1 root     root          1508 Jan 23 13:55 /usr/include/ql/config.sun.hpp
    

    This then causes OSRE to fail:

    libtool: compile:  g++ -DHAVE_CONFIG_H -I. -I../../qle -I../.. -I../.. -I/home/Engine-2a56688ff4d91e378bf88620a45864824150fbc5/QuantLib -g -O2 -Wall -MT averageonindexedcoupon.lo -MD -MP -MF .deps/averageonindexedcoupon.Tpo -c averageonindexedcoupon.cpp  -fPIC -DPIC -o .libs/averageonindexedcoupon.o
    In file included from /usr/include/ql/time/frequency.hpp:30:0,
                     from /usr/include/ql/time/period.hpp:30,
                     from /usr/include/ql/time/date.hpp:32,
                     from /usr/include/ql/event.hpp:28,
                     from /usr/include/ql/cashflow.hpp:28,
                     from /usr/include/ql/cashflows/coupon.hpp:28,
                     from /usr/include/ql/cashflows/floatingratecoupon.hpp:32,
                     from ../../qle/cashflows/averageonindexedcoupon.hpp:28,
                     from averageonindexedcoupon.cpp:19:
    /usr/include/ql/qldefines.hpp:91:28: fatal error: ql/config.hpp: No such file or directory
        #include <ql/config.hpp>
    

    In case it helps, my Dockerfile for QuantLib is as follows:

    ARG quantlib_hash=a00d43fabf30ab1e7fcaeaa9f497a551b0de528c
    RUN cd /home && \
        wget https://github.com/lballabio/QuantLib/archive/${quantlib_hash}.zip && \
        unzip ${quantlib_hash}.zip && \
        cd QuantLib-${quantlib_hash} && \
        mkdir build && \
        cd build && \
        cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INSTALL_PREFIX=/usr .. && \
        make -j3 && \
        make install && \
        cd /home && \
        rm -rf QuantLib-${quantlib_hash} ${quantlib_hash}.zip
    

    Where the hash is of the latest commit in master at present. Any ideas on what I am doing wrong are greatly appreciated.

    Cheers

    Marco

    [1] https://github.com/OpenSourceRisk/Engine

  • Impossible greek values returned by FD American

    Impossible greek values returned by FD American

    Here are some screenshots of parameters and the corresponding impossible gamma and vega (very negative) values which makes me question the rest of the greeks as well. I'm attaching the full scheme used to price using those parameters.

    class OptionPricer(object):
        def __init__(self):
            self.calc_date = pd.to_datetime('2019-09-10')
            self.calc_date_ql = ql.Date(self.calc_date.day, self.calc_date.month, self.calc_date.year)
            self.settlement = self.calc_date_ql
            self.day_count = ql.Actual365Fixed()
            self.calendar = ql.UnitedStates()
            ql.Settings.instance().evaluationDate = self.calc_date_ql
            period = ql.Period(int(10), ql.Days)
            self.maturity_date = self.calendar.advance(ql.Date(10, 9, 2019), period)
            self.eu_exercise = ql.EuropeanExercise(self.maturity_date)
            self.am_exercise = ql.AmericanExercise(self.settlement, self.maturity_date)
            self.payoff = ql.PlainVanillaPayoff(ql.Option.Put, 110)
            self.am_option = ql.VanillaOption(self.payoff, self.am_exercise)
            self.eu_option = ql.VanillaOption(self.payoff,self.eu_exercise)
            self.spot_quote = ql.SimpleQuote(100)
            self.spot_handle = ql.QuoteHandle(self.spot_quote)
            self.vol_quote = ql.SimpleQuote(0.1)
            self.vol_handle = ql.QuoteHandle(self.vol_quote)
            self.rf_quote = ql.SimpleQuote(0.05)
            self.rf_handle = ql.QuoteHandle(self.rf_quote)
            self.div_quote = ql.SimpleQuote(0.05)
            self.div_handle = ql.QuoteHandle(self.div_quote)
            self.rf_flat_curve = ql.YieldTermStructureHandle(
                ql.FlatForward(self.calc_date_ql, self.rf_handle, self.day_count)
            )
            self.div_flat_curve = ql.YieldTermStructureHandle(
                ql.FlatForward(self.calc_date_ql, self.div_handle, self.day_count)
            )
            self.vol_flat_curve = ql.BlackVolTermStructureHandle(
                ql.BlackConstantVol(self.calc_date_ql, self.calendar, self.vol_handle, self.day_count)
            )
            self.bsm_process = ql.BlackScholesMertonProcess(self.spot_handle, self.div_flat_curve, self.rf_flat_curve, self.vol_flat_curve)
            self.engine = ql.FdBlackScholesVanillaEngine(self.bsm_process)
            self.eu_engine = ql.AnalyticEuropeanEngine(self.bsm_process)
    
            
        def numeric_first_order(self,option, quote, h = 0.0001):
            sigma0 = quote.value()
            quote.setValue(sigma0 - h)
            P_minus = option.NPV()
            quote.setValue(sigma0 + h)
            P_plus = option.NPV()
            quote.setValue(sigma0)
            return (P_plus - P_minus) / (2*h)
        
        
        def price_and_greeks(self,div_rate, rf_rate, vol, spot_price, strike_price, put_call, dte, market_price=None):
            period = ql.Period(int(dte), ql.Days)
            self.maturity_date = self.calendar.advance(self.calc_date_ql, period)
            self.am_exercise = ql.AmericanExercise(self.settlement, self.maturity_date)
    
            if put_call:
                self.payoff = ql.PlainVanillaPayoff(ql.Option.Put, strike_price)
            else:
                self.payoff = ql.PlainVanillaPayoff(ql.Option.Call, strike_price)
            
            
            T = self.day_count.yearFraction(self.calc_date_ql, self.maturity_date)
            N = max(200, int(1000 * T))
            M = max(100, int(200 *T))
            
            #self.engine = ql.FdBlackScholesVanillaEngine(self.bsm_process, M, N,int(0.2*M))
            self.engine = ql.FdBlackScholesVanillaEngine(self.bsm_process, M, N, 0, ql.FdmSchemeDesc.ImplicitEuler())
            #self.engine = ql.FdBlackScholesVanillaEngine(self.bsm_process, M, N, 0, ql.FdmSchemeDesc.TrBDF2())
            
            self.am_option = ql.VanillaOption(self.payoff, self.am_exercise)
            self.am_option.setPricingEngine(self.engine)    
            self.eu_exercise = ql.EuropeanExercise(self.maturity_date)
            self.eu_option = ql.VanillaOption(self.payoff,self.eu_exercise)
            self.eu_option.setPricingEngine(self.eu_engine)
            self.spot_quote.setValue(spot_price)
            self.vol_quote.setValue(vol)
            self.rf_quote.setValue(rf_rate)
            self.div_quote.setValue(div_rate)
            price = self.am_option.NPV()
            delta = self.am_option.delta()
            gamma = self.am_option.gamma()
            theta = self.am_option.theta()
            #if market_price is not None:
            #    print(self.am_option.impliedVolatility(market_price, self.bsm_process))
            #rho = self.numeric_first_order(self.am_option, self.rf_quote)
            vega = self.numeric_first_order(self.am_option, self.vol_quote)/100
            return price, delta, gamma, theta, vega, self.eu_option.NPV(), self.eu_option.delta(),self.eu_option.gamma(), self.eu_option.theta(), self.eu_option.vega()/100 #, rho    
    
    Screen Shot 2020-03-02 at 4 12 23 PM Screen Shot 2020-03-02 at 4 12 08 PM
  • Adding stdcall build config

    Adding stdcall build config

    Modifying QuantLib project file to add an stdcall build configuration. Also modified the vc14 solution file to add a minimal build for both Debug and Release. This is for use with QuantLib-SWIG for C#.

  • Add CMake Presets

    Add CMake Presets

    Closes #1207.

    To start with, it includes the following presets:

    • Linux with GCC
    • Linux with Clang
    • Windows with MSVC (x64)
    • Windows with Clang (x64)

    Unfortunately I do not have a Mac, so was unable to add or test presets for that platform.

  • [WIP] Add CMake support for Windows (MSVC)

    [WIP] Add CMake support for Windows (MSVC)

    This PR closes #326.

    Main changes:

    • Generate static and shared library projects (although nothing is exported from shared one) with meaningful names
    • Propagate QL_LINK_LIBRARY variable with the name of QuantLib library to be linked against (static one).
    • Use full qualified name for lib and dll files: i.e.: QuantLib-vc140-mt-s-gd.lib
      • I needed to put a dash after the static suffix -s due to the way CMake's handles CMAKE_DEBUG_POSTFIX
    • Modify vcproj (visual studio file) in order to generate static QuantLib library with proper name (matching that generated by auto_link.hpp).
    • Set Boost_USE_STATIC_LIBS variable to ON in order to match boost libraries automatically linked.

    Let's start to talk about all these changes.

  • Fix the accrual calculation for OvernightIndexedCoupon

    Fix the accrual calculation for OvernightIndexedCoupon

    Fix the accrual calculation for OvernightIndexedCoupon by overriding accruedAmount() in OvernightIndexedCoupon and passing date to new overload rate() function.

    fixes issue #1214

  • Index::hasHistoricalFixing(fixingDate)

    Index::hasHistoricalFixing(fixingDate)

    I have added to ql/cashflows/floatingratecoupon.hpp

            //! whether or not the coupon is already fixed
            virtual bool isFixed() const;
    

    to check if the coupon is fixed or not. Before and after the fixing date it is obvious and at the fixing date I am using the approach for the InterestRateIndex::fixing(...) here

    https://github.com/lballabio/QuantLib/blob/a44b404a3361b625c068173a5c8e0bb9981ea374/ql/indexes/interestrateindex.cpp#L85

    I was conservative by not using c++11 features within the implementation:

        bool FloatingRateCoupon::isFixed() const {
            Date fixingDate = this->fixingDate();
            Date today = Settings::instance().evaluationDate();
    
            /* We compare serialNumber() here in case QL_HIGH_RESOLUTION_DATE is defined
             * to avoid comparing dateTimes(). */
            if (today.serialNumber() != fixingDate.serialNumber()) {
                return (fixingDate.serialNumber() < today.serialNumber());
            } else {
                try {
                    // might have been fixed, see InterestRateIndex::fixing(...)
                    Rate result = index_->pastFixing(fixingDate);
                    return result != Null<Real>();
                } catch (Error&) {
                    return false;
                }
            }
        }
    

    however the testcase I have written seems to have problems with my c++11 features only on macos.

    Also I am not sure if the implementation needs to be overwritten in derived coupon classes like IborCoupon, OvernightIndexedCoupon etc.

  • Test market model failed in VC 14.1

    Test market model failed in VC 14.1

    I compiled test-suite a few days ago and run it today. Environment : Windows 10 + Visual Studio 2017. It's still running but I can see one of them is failed already.

    Testing pathwise vegas in a lognormal forward rate market model...
    ../test-suite/marketmodel.cpp(3622): fatal error: in "QuantLib test suite/Market-model tests/QuantLib__detail__quantlib_test_case(&MarketModelTest__testPathwiseVegas)": caps Pathwise vega test fails : 1
    
  • Improve validation for barrier option engines when the spot has breached the barrier price level

    Improve validation for barrier option engines when the spot has breached the barrier price level

    At the inception of barrier options, the prices are away from barrier price levels however during the life of the option, the underlying could breach the barrier levels. In that case, the knock-out options cease to exist and knock-in options become effective as normal options. The error message which shows up currently is "RunTimeerror for interpolation range" for FdBlackScholesBarrierEngine in the case the spot is beyond barrier price i.e. spot less than the barrier price for down-in and down-out and more than barrier price for up-in and up-out options. These should be improved for a better understanding of the user.

    For more details, refer to communication on users email list timed 2022-06-21 06:31:03 on below link: https://sourceforge.net/p/quantlib/mailman/message/37670545/ entire thread: https://sourceforge.net/p/quantlib/mailman/quantlib-users/thread/CADOha%3DL8QzNx-ZKn7hi1zHU6oJazwQcwRUCkt0oy6yiAr3c0yQ%40mail.gmail.com/#msg37670545

  • Bug in ACT/ACT ISMA

    Bug in ACT/ACT ISMA

    I am using QuantLib 1.24 in WSL and I seem to find a bug in ActualActual for ISMA. The following code

    #include <ql/time/daycounters/actualactual.hpp>
    #include <ql/time/date.hpp>
    #include <iostream>
    
    using namespace QuantLib;
    
    int main() {
        DayCounter actact = ActualActual(ActualActual::Convention::ISMA);
    
        std::cout << "2021-12-01--->2022-02-15: "
                  << actact.yearFraction(Date(1, December, 2021),
                                         Date(15, February, 2022))
                  << std::endl;
        std::cout << "2021-12-31--->2022-02-15: "
                  << actact.yearFraction(Date(31, December, 2021),
                                         Date(15, February, 2022))
                  << std::endl;
        std::cout << "2022-01-01--->2022-02-15: "
                  << actact.yearFraction(Date(1, January, 2022),
                                         Date(15, February, 2022))
                  << std::endl;
        std::cout << "2022-01-30--->2022-02-15: "
                  << actact.yearFraction(Date(30, January, 2022),
                                         Date(15, February, 2022))
                  << std::endl;
        std::cout << "2022-01-31--->2022-02-15: "
                  << actact.yearFraction(Date(31, January, 2022),
                                         Date(15, February, 2022))
                  << std::endl;
        std::cout << "2022-02-01--->2022-02-15: "
                  << actact.yearFraction(Date(1, February, 2022),
                                         Date(15, February, 2022))
                  << std::endl;
        return 0;
    }
    

    produces

    2021-12-01--->2022-02-15: 0.166667
    2021-12-31--->2022-02-15: 0.166667
    2022-01-01--->2022-02-15: 0.0833333
    2022-01-30--->2022-02-15: 0.0833333
    2022-01-31--->2022-02-15: 0.0410959
    2022-02-01--->2022-02-15: 0.0383562
    

    This does not seem to be consistent with the ACT/ACT ISMA convention.

  • Constructing one-day swaps in the vicinity of holidays throws schedule exceptions

    Constructing one-day swaps in the vicinity of holidays throws schedule exceptions

    I'm not sure how much of this, if any, is a bug.

    One of my users tried to create a series of one-day swaps starting on each of a span of weekdays, as a way of getting a crude plot of a yield curve. This resulted in "degenerate single date" exceptions in many cases. In particular, it resulted in these exceptions in some cases where the start date was not a holiday, which surprised me. Here are three cases in the year from today:

    2022-07-29
    is business day: yes
    adjusted: 2022-07-29
    following: 2022-08-01
    exception: degenerate single date (July 29th, 2022) schedule
     seed date: July 30th, 2022
     exit date: July 29th, 2022
     effective date: July 29th, 2022
     first date: null date
     next to last date: null date
     termination date: July 30th, 2022
     generation rule: Backward
     end of month: 0
    
    2022-12-30
    is business day: yes
    adjusted: 2022-12-30
    following: 2023-01-03
    exception: degenerate single date (December 30th, 2022) schedule
     seed date: December 31st, 2022
     exit date: December 30th, 2022
     effective date: December 30th, 2022
     first date: null date
     next to last date: null date
     termination date: December 31st, 2022
     generation rule: Backward
     end of month: 0
    
    2023-04-28
    is business day: yes
    adjusted: 2023-04-28
    following: 2023-05-02
    exception: degenerate single date (April 28th, 2023) schedule
     seed date: April 29th, 2023
     exit date: April 28th, 2023
     effective date: April 28th, 2023
     first date: null date
     next to last date: null date
     termination date: April 29th, 2023
     generation rule: Backward
     end of month: 0
    

    I think what's happening here is that the end date falls on a holiday, so it gets adjusted, but using the modified following rule, which adjusts it backwards, making it the same as the start date. Does this seem correct?

    I see similar exceptions when creating two- and three-day swaps, if i search enough start dates.

    What i would really like is to be able to ask for a swap starting on any date (ideally including holidays), of any tenor, and for the dates to be adjusted in some way that results in a valid swap. Is there a way to achieve this?

    I don't mind adjusting the start date myself. But i can't see any way to make a manual adjustment of a calculated end date before an exception is thrown.

    OneDaySwapDemo.cpp.txt

  • BBSW fixing days seems wrong

    BBSW fixing days seems wrong

    Hi,

    BBSW fixing days (aka settlement days) is currently set to 0. https://github.com/lballabio/QuantLib/blob/922e582a0d59f20d5a4480448546942c64490fda/ql/indexes/ibor/bbsw.hpp#L44-L46

    I believe this is wrong, and it should be 1 day. This is supported by what I see on Bloomberg ICVS 303 (BBSW3M), see screenshot below.

    bbsw

  • MakeVanillaSwap / MakeOIS withSettlementDays clears an explicit effective date

    MakeVanillaSwap / MakeOIS withSettlementDays clears an explicit effective date

    MakeVanillaSwap and MakeOIS both allow customisation of the swap's settlement days (via withSettlementDays) and effective date (via withEffectiveDate). The settlement days is used to compute the spot date from the reference data, as part of working out the start date in the absence of an explicit effective date (start date and effective date are synonyms, right?).

    However, setting the settlement days has the (to me, quite surprising) additional effect of clearing an explicit effective date. So, if MakeVanillaSwap is used to customise the effective date and also the settlement days, the resulting swap will have a start date at spot, not at the specified effective date.

    In particular, that means that these two swaps have different dates (see attached code for a complete example):

      shared_ptr<VanillaSwap> swapSettlementDaysThenEffectiveDate =
          MakeVanillaSwap(tenor, index).withSettlementDays(2).withEffectiveDate(effectiveDate);
    
      shared_ptr<VanillaSwap> swapEffectiveDateThenSettlementDays =
          MakeVanillaSwap(tenor, index).withEffectiveDate(effectiveDate).withSettlementDays(2);
    

    with_settlement_days_example.cpp.txt

    This strikes me as highly dubious!

    Is this intentional? What is the rationale for this?

    I appreciate that it may seem nonsensical to set both the effective date and the settlement days, given that they are mutually exclusive ways of setting the start date. But this happens in my code because we have some common setup code used to prepare swaps of various kinds; it always sets the settlement days, and optionally sets the effective date. As it happens, it set the effective date first, so it was getting cleared.

    EDIT: The previous paragraph is slightly wrong. I was uselessly setting the settlement days because i have a custom rate helper, which is mostly copied from SwapRateHelper (great artists steal!), and which takes the settlement days as a parameter. I see that since i took that copy, you made commit 0ec47814f which changes the way settlement days are handled, and would avoid this bug. I should update my code!

    If you want to enforce mutual exclusiveness of these two ways of setting the start date, can i suggest doing it by means of assertions, rather than one silently dominating the other? Remove the line which clears the effective date, and instead, in the build method, do something like:

    QL_ASSERT(effectiveDate_ == Date() || (settlementDays_ == Null<Natural>() && forwardStart_ == 0*Days), "make your mind up!");
    

    I'm happy to write a PR if you think this is a good idea.

    if not that, could this behaviour at least be documented in a comment on withSettlementDays?

Libft is an individual project at 42 that requires us to re-create some standard C library functions including some additional ones that can be used later to build a library of useful functions for the rest of the program.
Libft is an individual project at 42 that requires us to re-create some standard C library functions including some additional ones that can be used later to build a library of useful functions for the rest of the program.

Libft is an individual project at 42 that requires us to re-create some standard C library functions including some additional ones that can be used later to build a library of useful functions for the rest of the program.

Apr 5, 2022
Oct 6, 2021
F Graphics Library (FGL) is a small graphics C++ portable library for LCD displays on embedded systems

F Graphics Library (FGL) Full documentation: fgl.docsforge.com (By Filipe Chagas) F Graphics Library is a C++ library that I created for use in embedd

Dec 14, 2021
Itpp - IT++ library mirror/fork. C++ library of mathematical, signal processing and communication classes and functions.

Introduction ************ IT++ is a C++ library of mathematical, signal processing and communication classes and functions. Its main use is in simula

Apr 9, 2022
2D physics header-only library for videogames developed in C using raylib library.
2D physics header-only library for videogames developed in C using raylib library.

Physac Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop to simluate physics. A physics step contai

Jun 13, 2022
This is a helper library to abstract away interfacing with floppy disk drives in a cross-platform and open source library.
This is a helper library to abstract away interfacing with floppy disk drives in a cross-platform and open source library.

Adafruit Floppy This is a helper library to abstract away interfacing with floppy disk drives in a cross-platform and open source library. Adafruit Fl

Jun 22, 2022
`lv_lib_100ask` is a reference for various out of the box schemes based on lvgl library or an enhanced interface for various components of lvgl library.

Introduction lv_lib_100ask is a reference for various out of the box schemes based on lvgl library or an enhanced interface for various components of

Jun 14, 2022
QtVerbalExpressions - This Qt lib is based off of the C++ VerbalExpressions library. [MIT]

QtVerbalExpressions Qt Regular Expressions made easy This Qt lib is based off of the C++ VerbalExpressions library by whackashoe. Testing if we have a

May 12, 2022
A header-only library for C++(0x) that allows automagic pretty-printing of any container.

cxx-prettyprint =============== A pretty printing library for C++ containers. Synopsis: Simply by including this header-only library in your sourc

Jun 9, 2022
A standalone and lightweight C library

Klib: a Generic Library in C Overview Klib is a standalone and lightweight C library distributed under MIT/X11 license. Most components are independen

Jun 15, 2022
a small C library for x86 CPU detection and feature extraction

libcpuid libcpuid provides CPU identification for the x86 (and x86_64). For details about the programming API, you might want to take a look at the pr

May 31, 2022
NIH Utility Library

libnih is a light-weight "standard library" of C functions to ease the development of other libraries and applications. Its goals are: * despite it

Mar 23, 2022
Functional programming style pattern-matching library for C++
Functional programming style pattern-matching library for C++

Mach7: Pattern Matching for C++ by Yuriy Solodkyy, Gabriel Dos Reis, Bjarne Stroustrup Abstract Pattern matching is an abstraction mechanism that can

Jun 24, 2022
Cross-platform C++11 header-only library for memory mapped file IO

mio An easy to use header-only cross-platform C++11 memory mapping library with an MIT license. mio has been created with the goal to be easily includ

Jun 15, 2022
Parsing Expression Grammar Template Library
Parsing Expression Grammar Template Library

Welcome to the PEGTL The Parsing Expression Grammar Template Library (PEGTL) is a zero-dependency C++ header-only parser combinator library for creati

Jun 23, 2022
Simple Dynamic Strings library for C

Simple Dynamic Strings Notes about version 2: this is an updated version of SDS in an attempt to finally unify Redis, Disque, Hiredis, and the stand a

Jun 19, 2022
Semantic version library written in ANSI C

semver.c Semantic version v2.0 parser and render written in ANSI C with zero dependencies. Features Standard compliant (otherwise, open an issue) Vers

May 16, 2022
Cross-platform, Serial Port library written in C++

Serial Communication Library (Linux and OS X) (Windows) This is a cross-platform library for interfacing with rs-232 serial like ports written in C++.

Jun 19, 2022
ZXing ("Zebra Crossing") barcode scanning library for Java, Android
ZXing (

Project in Maintenance Mode Only The project is in maintenance mode, meaning, changes are driven by contributed patches. Only bug fixes and minor enha

Jun 17, 2022