0

I would like to derive a class template from QuantLib::PiecewiseYieldCurve. This is my derived class definition:

#include <ql\termstructures\yield\piecewiseyieldcurve.hpp>
#include <MarKetQuote\include\OISQuote.h>
#include <vector>

using namespace QuantLib;

/*! \brief Class to bootstrap an OIS curve.
*/
template <class Traits, class Interpolator,
    template <class> class Bootstrap = IterativeBootstrap>
class OISCurve : public PiecewiseYieldCurve < Traits, Interpolator, Bootstrap >
{
private:
    /** Typedef to refer to the specialized class.
    It was necessary to add it in other to be able to declare the constructor as in QuantLib::PiecewiseYieldCurve.
    */
    typedef OISCurve<Traits, Interpolator, Bootstrap> this_ois_curve;
public:
    /** Constructor.
    */
    OISCurve(
        const Date& referenceDate,
        const std::vector<OISQuote>& quotes,
        const DayCounter& dayCounter,
        Real accuracy,
        const Interpolator& i = Interpolator(),
        const Bootstrap<this_ois_curve>& bootstrap = Bootstrap<this_ois_curve>());
};

OISQuote is simply a class derived from QuantLib::SimpleQuote. I'm not familiar with this type of complicated templating, but to my limited understanding the above should be ok. It compiles actually. The problem arises when I try to instantiate a specialized class like this:

OISCurve<Discount, LogLinear> oisCurve = OISCurve<Discount, LogLinear>(Date::todaysDate(), quotes, Actual360(), 1.0e-12);

I get a linking error LNK2019 (using visual studio):

main.obj : error LNK2019: unresolved external symbol "public: __cdecl OISCurve<struct QuantLib::Discount,class QuantLib::LogLinear,class QuantLib::IterativeBootstrap>::OISCurve<struct QuantLib::Discount,class QuantLib::LogLinear,class QuantLib::IterativeBootstrap>(class QuantLib::Date const &,class std::vector<class OISQuote,class std::allocator<class OISQuote> > const &,class QuantLib::DayCounter const &,double,class QuantLib::LogLinear const &)" (??0?$OISCurve@UDiscount@QuantLib@@VLogLinear@2@VIterativeBootstrap@2@@@QEAA@AEBVDate@QuantLib@@AEBV?$vector@VOISQuote@@V?$allocator@VOISQuote@@@std@@@std@@AEBVDayCounter@2@NAEBVLogLinear@2@@Z) referenced in function main
1>C:\Users\u8998\PricingEngine\build\Debug\main.exe : fatal error LNK1120: 1 unresolved externals

Thanks for the help.

EDIT:

Sorry for the late reply. Thank you @LuigiBallabio and @StudentT for your answers. My problem ended up being caused by my inexperience with class templates. I had my declaration in a header file and my implementation in a cpp file exactly as with any other class. Following the guidelines in the accepted answer of this question I modified my code accordingly:

OISCurve.h

#ifndef OIS_CURVE_H
#define OIS_CURVE_H

#include <ql\termstructures\yield\piecewiseyieldcurve.hpp>
#include <ql\termstructures\yield\ratehelpers.hpp>
#include <ql\quote.hpp>
#include <vector>
#include <boost\shared_ptr.hpp>

using namespace QuantLib;


template <class Traits, class Interpolator,
    template <class> class Bootstrap = IterativeBootstrap>
class OISCurve : public PiecewiseYieldCurve < Traits, Interpolator, Bootstrap >
{
public:

    OISCurve(const Date& referenceDate,
        const std::vector<boost::shared_ptr<Quote>>& quotes,
        const DayCounter& dayCounter,
        Real accuracy);

    friend std::vector<boost::shared_ptr<RateHelper>> getRateHelpers(const std::vector<boost::shared_ptr<Quote>>& quotes);

private:
    std::vector<boost::shared_ptr<Quote>> quotes_;
};

#include <CurveBootstrapping\src\OISCurve.cpp>

#endif

OISCurve.cpp

#include "OISCurve.h"
#include <ql\errors.hpp>
#include <algorithm>
#include <boost\foreach.hpp>
#include <ql\termstructures\yield\oisratehelper.hpp>
#include <MarKetQuote\include\OISQuote.h>
#include <ql\handle.hpp>
#include <ql\indexes\ibor\eonia.hpp>

#ifndef OIS_CURVE_IMPL
#define OIS_CURVE_IMPL

template <class T, class I, template <class> class B>
OISCurve<T, I, B>::OISCurve(
    const Date& referenceDate,
    const std::vector<boost::shared_ptr<Quote>>& quotes,
    const DayCounter& dayCounter,
    Real accuracy)
    : PiecewiseYieldCurve < T, I, B >(referenceDate, 
    initializeQuotesAndGetRateHelpers(quotes), 
    dayCounter, 
    accuracy)
{
    std::cout << "constructor works" << std::endl;
}

std::vector<boost::shared_ptr<RateHelper>> getRateHelpers(const std::vector<boost::shared_ptr<Quote>>& quotes)
{

    QL_REQUIRE(std::all_of(quotes.begin(), quotes.end(), [](boost::shared_ptr<Quote> quote){ return boost::dynamic_pointer_cast<OISQuote>(quote) != 0; }),
        "All quotes must be OISQuotes!");

    std::vector<boost::shared_ptr<RateHelper>> rateHelpers;
    BOOST_FOREACH(boost::shared_ptr<Quote> quote, quotes)
    {
        rateHelpers.push_back(boost::shared_ptr<RateHelper>(new OISRateHelper(2,
            boost::dynamic_pointer_cast<OISQuote>(quote)->tenor(),
            Handle<Quote>(quote),
            boost::shared_ptr<OvernightIndex>(new Eonia()))));
    }

    return rateHelpers;
}

#endif

This is the solution i liked the most.

Community
  • 1
  • 1
  • This question belongs on stack exchange as its programming related. – chollida Aug 28 '15 at 15:28
  • 1
    hmm quantlib is the biggest open source coding project for quantitative finance and the question is about how to use it so I think it belongs more on quant.stackexchange.com – Mark Joshi Aug 29 '15 at 00:17

1 Answers1

1

I don't think this questions relates to quantitative finance at all, but I'll answer anyway.

You have not provided an implementation to the constructor of the class OISCurve.

To link your program, do this:

OISCurve(
    const Date& referenceDate,
    const std::vector<OISQuote>& quotes,
    const DayCounter& dayCounter,
    Real accuracy,
    const Interpolator& i = Interpolator(),
    const Bootstrap<this_ois_curve>& bootstrap = Bootstrap<this_ois_curve>())
: <Call Parent Constructor>
{

}

You will need to replace with a call to an actual constructor defined in PiecewiseYieldCurve. There are six such constructors, so you will need to select the one that you think most appropriate. Please note that you will need to give the parent constructor a list of instruments, but it's missing in your constructor definition.

ABCD
  • 7,914
  • 9
  • 54
  • 90
  • 1
    It's not going to be easy to build the list of required helpers in the initialization list, though. In this case, instead of inheriting a class I'd go for a function that takes the required inputs, builds the list of helpers, and returns an instance of `PiecewiseYieldCurve`. – Luigi Ballabio Aug 29 '15 at 12:05
  • @LuigiBallabio Yes, I agree. From the definitions above, it's pretty hard to construct the class PiecewiseYieldCurve. In fact, I think the poster is confused. He should only inherit the PiecewiseYieldCurve if he wants to provide a better bootstrapping strategy, but I don't think this is the case here. He just wants a custom way to construct a curve. – ABCD Aug 29 '15 at 13:30