packages feed

hasquant-0.7.0.0: cbits/qlMisc.cpp

#include <ql/settings.hpp>
#include <ql/patterns/observable.hpp>
#include <ql/version.hpp>
#include <ql/errors.hpp>
#include <ql/time/date.hpp>
#include <ql/currencies/all.hpp>
#include <ql/currencies/exchangeratemanager.hpp>
#include <ql/exchangerate.hpp>
#include <ql/money.hpp>
#include <ql/interestrate.hpp>
#include <ql/math/optimization/all.hpp>
#include <ql/timegrid.hpp>
#include <ql/math/rounding.hpp>
#include <ql/quotes/all.hpp>
#include <ql/time/date.hpp>
#include <ql/time/imm.hpp>
#include <ql/time/ecb.hpp>
#include <ql/time/calendar.hpp>
#include <ql/time/calendars/all.hpp>
#include <ql/time/schedule.hpp>
#include <ql/time/period.hpp>
#include <ql/utilities/dataparsers.hpp>
#include <ql/time/daycounters/all.hpp>
#include <ql/experimental/commodities/commoditytype.hpp>
#include <ql/experimental/commodities/unitofmeasure.hpp>
#include <ql/experimental/commodities/petroleumunitsofmeasure.hpp>
#include <ql/experimental/commodities/paymentterm.hpp>
#include <ql/experimental/commodities/quantity.hpp>
#include <ql/experimental/commodities/unitofmeasureconversion.hpp>
#include <ql/experimental/commodities/unitofmeasureconversionmanager.hpp>
#include <ql/experimental/commodities/commoditysettings.hpp>
#include <ql/index.hpp>
#include <ql/math/statistics/sequencestatistics.hpp>
#include <ql/math/statistics/riskstatistics.hpp>
#include <ql/math/array.hpp>
#include <ql/math/matrixutilities/symmetricschurdecomposition.hpp>
#include <ql/math/matrixutilities/pseudosqrt.hpp>
#include <ql/math/matrixutilities/choleskydecomposition.hpp>
#include <ql/prices.hpp>
#include <ql/models/volatility/garch.hpp>
#include <ql/models/volatility/garmanklass.hpp>
#include <ql/models/volatility/constantestimator.hpp>
#include <ql/models/volatility/simplelocalestimator.hpp>

#include <numeric>
#include <functional>

#include <cstdint>

#ifdef QLTRACK_ALLOCATIONS
# include <cstdlib>
#endif

#include "qlaux.h"
#include "qlMisc.h"
namespace hasquant {
#include "qlEnumObjects.h"
}

using namespace QuantLib;

namespace {
  class SavedSettingsWithObservable {
    public:
      SavedSettingsWithObservable()
      : updatesEnabled_(ObservableSettings::instance().updatesEnabled()),
        updatesDeferred_(ObservableSettings::instance().updatesDeferred()) {}

      ~SavedSettingsWithObservable() {
        try {
          auto& settings = ObservableSettings::instance();
          if (updatesEnabled_)
            settings.enableUpdates();
          else
            settings.disableUpdates(updatesDeferred_);
        } catch (...) {
        }
      }

    private:
      bool updatesEnabled_;
      bool updatesDeferred_;
      SavedSettings savedSettings_;
  };

  // Adapts a Haskell callback to CostFunction, crossing the FFI once per whole-vector value().
  // No bound caller requires the multi-output values() operation.
  class HsCostFunction : public CostFunction {
    public:
      explicit HsCostFunction(double (*fn)(double*, unsigned)) : fn_(fn) {}
      Real value(const Array& x) const override {
        std::vector<double> xs(x.begin(), x.end());
        return fn_(xs.data(), (unsigned)xs.size());
      }
      Array values(const Array&) const override {
        QL_FAIL("HsCostFunction::values not implemented");
      }
    private:
      double (*fn_)(double*, unsigned);
  };

  // Quote composition remains inside QuantLib's observer graph so dependent objects update.
  // Runtime operation catalogues and Haskell callbacks each need one functor instantiation.
  struct QuoteUnaryOp {
    int op;
    Real operand;
    Real operator()(Real x) const {
      switch (op) {
      case hasquant::QuoteAdd: return x + operand;
      case hasquant::QuoteSubtract: return x - operand;
      case hasquant::QuoteMultiply: return x * operand;
      case hasquant::QuoteDivide: return x / operand;
      }
      QL_FAIL("unknown QuoteOp " << op);
    }
  };

  struct QuoteBinaryOp {
    int op;
    Real operator()(Real x, Real y) const {
      switch (op) {
      case hasquant::QuoteAdd: return x + y;
      case hasquant::QuoteSubtract: return x - y;
      case hasquant::QuoteMultiply: return x * y;
      case hasquant::QuoteDivide: return x / y;
      }
      QL_FAIL("unknown QuoteOp " << op);
    }
  };

  // MultiCompositeQuote imposes no non-empty requirement (isValid() is all_of over the elements,
  // vacuously true), so an empty input is accepted and yields the fold's identity.
  struct QuoteArrayOp {
    int op;
    Real operator()(const Array& a) const {
      switch (op) {
      case hasquant::QuoteSum: return std::accumulate(a.begin(), a.end(), Real(0.0));
      case hasquant::QuoteProduct: return std::accumulate(a.begin(), a.end(), Real(1.0), std::multiplies<Real>());
      case hasquant::QuoteNorm2: return Norm2(a);
      }
      QL_FAIL("unknown MultiQuoteOp " << op);
    }
  };

  // Named aliases rather than the instantiations spelled inline, because QL_TRACE_NAME is a macro
  // and CompositeQuote<double (*)(double, double)> reads as two macro arguments.
  using OpDerivedQuote = DerivedQuote<QuoteUnaryOp>;
  using OpCompositeQuote = CompositeQuote<QuoteBinaryOp>;
  using OpMultiCompositeQuote = MultiCompositeQuote<QuoteArrayOp>;
  using HsDerivedQuote = DerivedQuote<double (*)(double)>;
  using HsCompositeQuote = CompositeQuote<double (*)(double, double)>;
  // MultiCompositeQuote calls its ArrayFunction with an Array, so unlike the unary/binary cases
  // (where a plain double(*)(double...) is already a usable functor) the C function pointer needs
  // a thin adapter. It is still handed the whole state vector per evaluation, so this crosses the
  // language boundary once per value(), not once per element.
  struct HsArrayFun {
    double (*fn)(const double*, unsigned);
    Real operator()(const Array& a) const {return fn(a.begin(), (unsigned)a.size());}
  };
  using HsMultiCompositeQuote = MultiCompositeQuote<HsArrayFun>;

  RiskStatistics riskStats(unsigned n, double *xs) {
    RiskStatistics s;
    s.addSequence(xs, xs+n);
    return s;
  }
  // Shared TimeSeries<Real> marshalling for real-valued volatility estimators.
  void realSeriesCalculate(const std::function<TimeSeries<Volatility>(const TimeSeries<Real>&)>& calc,
      unsigned len, int *dates, double *values,
      unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
    OutArrayResult<int> dateResult(outDatesLen, outDates);
    OutArrayResult<double> valueResult(outValuesLen, outValues);
    try {
      TimeSeries<Real> ts;
      for (unsigned n = 0; n < len; ++n) ts[Date(dates[n])] = values[n];
      TimeSeries<Volatility> out = calc(ts);
      const std::vector<Date> outDs = out.dates();
      const std::vector<Volatility> outVs = out.values();
      int *ds = dateResult.allocate((unsigned)outDs.size());
      double *vs = valueResult.allocate((unsigned)outVs.size());
      for (unsigned n = 0; n < outDs.size(); ++n) ds[n] = outDs[n].serialNumber();
      for (unsigned n = 0; n < outVs.size(); ++n) vs[n] = outVs[n];
      dateResult.commit(); valueResult.commit();
    } catch (std::exception& er) {*e = tracedup(er.what());}
  }

  // TimeSeries<IntervalPrice> marshalling for the Garman-Klass estimators.
  void intervalPriceSeriesCalculate(const std::function<TimeSeries<Volatility>(const TimeSeries<IntervalPrice>&)>& calc,
      unsigned len, int *dates, double *opens, double *closes, double *highs, double *lows,
      unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
    OutArrayResult<int> dateResult(outDatesLen, outDates);
    OutArrayResult<double> valueResult(outValuesLen, outValues);
    try {
      TimeSeries<IntervalPrice> ts;
      for (unsigned n = 0; n < len; ++n) ts[Date(dates[n])] = IntervalPrice(opens[n], closes[n], highs[n], lows[n]);
      TimeSeries<Volatility> out = calc(ts);
      const std::vector<Date> outDs = out.dates();
      const std::vector<Volatility> outVs = out.values();
      int *ds = dateResult.allocate((unsigned)outDs.size());
      double *vs = valueResult.allocate((unsigned)outVs.size());
      for (unsigned n = 0; n < outDs.size(); ++n) ds[n] = outDs[n].serialNumber();
      for (unsigned n = 0; n < outVs.size(); ++n) vs[n] = outVs[n];
      dateResult.commit(); valueResult.commit();
    } catch (std::exception& er) {*e = tracedup(er.what());}
  }
}

#ifdef QLTRACK_ALLOCATIONS
// Destination is the QLTRACK_ALLOCATIONS env var when set, else the compile-time
// default the flag bakes in (stderr, spelled differently per platform). Without the
// env var the only way to send a trace to a file was to recompile with a different
// -DQLTRACK_ALLOCATIONS, and redirecting stderr also swallows the program's own
// output -- which matters here because a trace is only useful next to the values it
// explains.
static const char *qlTrackDestination() {
  const char *env = std::getenv("QLTRACK_ALLOCATIONS");
  return env && *env ? env : QLTRACK_ALLOCATIONS;
}
std::ostream &traceStream() {
  // Opened on first use, so it cannot lose a race with another translation unit's static
  // initialization -- which a plain global std::ofstream, constructed in this one, could.
  // Deliberately never destroyed: a trace emitted from a late static destructor must not
  // write to an already-closed stream, and the process is exiting anyway.
  static std::ofstream *stream = new std::ofstream(qlTrackDestination());
  return *stream;
}
// Same reason as qlInstrument.cpp's Hs* labels: these live in the anonymous namespace above and
// so cannot be named in qlaux.h's table, and without a specialization ObjClassName falls back to
// typeid().name() -- which for a template instantiation is especially unreadable. All six are
// shared_ptr payloads, alloc()-only and never explicitly freed, so alloc-summary.py shows them
// with no matching del by design.
QL_TRACE_NAME(OpDerivedQuote)
QL_TRACE_NAME(OpCompositeQuote)
QL_TRACE_NAME(OpMultiCompositeQuote)
QL_TRACE_NAME(HsDerivedQuote)
QL_TRACE_NAME(HsCompositeQuote)
QL_TRACE_NAME(HsMultiCompositeQuote)
#endif

int *qlAllocateInts(size_t size) {return ret(new int[size]);}
double *qlAllocateDoubles(size_t size) {return ret(new double[size]);}
const QuantLib::Date qlNullableDate(int serialNumber) {return !serialNumber ? Date() : Date(serialNumber);}
int qlNullableDate(const QuantLib::Date &date) {return date == Date() ? 0 : date.serialNumber();}
ext::optional<bool> qlOptBool(int b) {return b == -1 ? ext::nullopt : ext::optional<bool>(b);}
int qlOptBool(optional<bool> b) {return b ? *b : -1;}
ext::optional<BusinessDayConvention> qlOptBusinessDayConvention(int c) {return c == -1 ? ext::nullopt : ext::optional<BusinessDayConvention>((BusinessDayConvention)c);}

char *tracedup(const char *p) {
  trace("Duplicating string", (void *)p);
  char *dup = strdup(p);
  trace("Duplicate string", (void *)dup);
  return dup;
}

// The named-currency table. Each entry is a function pointer that heap-allocates one
// QuantLib currency subclass; the enum index into it is what Haskell passes.
//
// The return type is spelled `Currency *', not `C *': alloc() takes its trace label from its
// argument's static type, and the matching qlFreeCurrency frees through a `Currency *'. A
// deduced or derived return type here would silently label every allocation with its concrete
// subclass and leave all of them unmatched in alloc-summary.py.
template <class C> Currency *makeCurrency() {return new C();}

using makeCcy = Currency *(*)();

// The calendar table, in two flavours: a calendar with no market variants ignores the market
// argument, one with them maps it onto its own nested Market enum. Return type spelled as the
// base for the same reason as makeCurrency above.
template <class C> Calendar *makeCalendar(int) {return new C();}
template <class C> Calendar *makeMarketCalendar(int market) {return new C(static_cast<typename C::Market>(market));}

using makeCal = Calendar *(*)(int market);

// The day counter table: three constructor shapes -- no argument, a bool flag, or the class's
// own nested Convention enum. Return type spelled as the base, as with makeCurrency above.
template <class D> DayCounter *makeDayCounter(int) {return new D();}
template <class D> DayCounter *makeFlagDayCounter(int flag) {return new D(flag != 0);}
template <class D> DayCounter *makeConvDayCounter(int convention) {return new D(static_cast<typename D::Convention>(convention));}

using makeDc = DayCounter *(*)(int convention);

// must match the order of qlEnumObjects.h:Ccy
static const makeCcy ccys[] = {
    &makeCurrency<ARSCurrency>
  , &makeCurrency<ATSCurrency>
  , &makeCurrency<AUDCurrency>
  , &makeCurrency<BCHCurrency>
  , &makeCurrency<BDTCurrency>
  , &makeCurrency<BEFCurrency>
  , &makeCurrency<BGLCurrency>
  , &makeCurrency<BRLCurrency>
  , &makeCurrency<BTCCurrency>
  , &makeCurrency<BYRCurrency>
  , &makeCurrency<CADCurrency>
  , &makeCurrency<CHFCurrency>
  , &makeCurrency<CLPCurrency>
  , &makeCurrency<CNYCurrency>
  , &makeCurrency<COPCurrency>
  , &makeCurrency<CYPCurrency>
  , &makeCurrency<CZKCurrency>
  , &makeCurrency<DASHCurrency>
  , &makeCurrency<DEMCurrency>
  , &makeCurrency<DKKCurrency>
  , &makeCurrency<EEKCurrency>
  , &makeCurrency<ESPCurrency>
  , &makeCurrency<ETCCurrency>
  , &makeCurrency<ETHCurrency>
  , &makeCurrency<EURCurrency>
  , &makeCurrency<FIMCurrency>
  , &makeCurrency<FRFCurrency>
  , &makeCurrency<GBPCurrency>
  , &makeCurrency<GRDCurrency>
  , &makeCurrency<HKDCurrency>
  , &makeCurrency<HUFCurrency>
  , &makeCurrency<IDRCurrency>
  , &makeCurrency<IEPCurrency>
  , &makeCurrency<ILSCurrency>
  , &makeCurrency<INRCurrency>
  , &makeCurrency<IQDCurrency>
  , &makeCurrency<IRRCurrency>
  , &makeCurrency<ISKCurrency>
  , &makeCurrency<ITLCurrency>
  , &makeCurrency<JPYCurrency>
  , &makeCurrency<KRWCurrency>
  , &makeCurrency<KWDCurrency>
  , &makeCurrency<KZTCurrency>
  , &makeCurrency<LTCCurrency>
  , &makeCurrency<LTLCurrency>
  , &makeCurrency<LUFCurrency>
  , &makeCurrency<LVLCurrency>
  , &makeCurrency<MTLCurrency>
  , &makeCurrency<MXNCurrency>
  , &makeCurrency<MYRCurrency>
  , &makeCurrency<NGNCurrency>
  , &makeCurrency<NLGCurrency>
  , &makeCurrency<NOKCurrency>
  , &makeCurrency<NPRCurrency>
  , &makeCurrency<NZDCurrency>
  , &makeCurrency<PEHCurrency>
  , &makeCurrency<PEICurrency>
  , &makeCurrency<PENCurrency>
  , &makeCurrency<PKRCurrency>
  , &makeCurrency<PLNCurrency>
  , &makeCurrency<PTECurrency>
  , &makeCurrency<ROLCurrency>
  , &makeCurrency<RONCurrency>
  , &makeCurrency<RUBCurrency>
  , &makeCurrency<SARCurrency>
  , &makeCurrency<SEKCurrency>
  , &makeCurrency<SGDCurrency>
  , &makeCurrency<SITCurrency>
  , &makeCurrency<SKKCurrency>
  , &makeCurrency<THBCurrency>
  , &makeCurrency<TRLCurrency>
  , &makeCurrency<TRYCurrency>
  , &makeCurrency<TTDCurrency>
  , &makeCurrency<TWDCurrency>
  , &makeCurrency<UAHCurrency>
  , &makeCurrency<USDCurrency>
  , &makeCurrency<VEBCurrency>
  , &makeCurrency<VNDCurrency>
  , &makeCurrency<XRPCurrency>
  , &makeCurrency<ZARCurrency>
  , &makeCurrency<ZECCurrency>
  , &makeCurrency<AEDCurrency>
  , &makeCurrency<AOACurrency>
  , &makeCurrency<BGNCurrency>
  , &makeCurrency<BHDCurrency>
  , &makeCurrency<BWPCurrency>
  , &makeCurrency<CLFCurrency>
  , &makeCurrency<CNHCurrency>
  , &makeCurrency<COUCurrency>
  , &makeCurrency<EGPCurrency>
  , &makeCurrency<ETBCurrency>
  , &makeCurrency<GELCurrency>
  , &makeCurrency<GHSCurrency>
  , &makeCurrency<HRKCurrency>
  , &makeCurrency<JODCurrency>
  , &makeCurrency<KESCurrency>
  , &makeCurrency<LKRCurrency>
  , &makeCurrency<MADCurrency>
  , &makeCurrency<MKDCurrency>
  , &makeCurrency<MURCurrency>
  , &makeCurrency<MXVCurrency>
  , &makeCurrency<OMRCurrency>
  , &makeCurrency<PHPCurrency>
  , &makeCurrency<QARCurrency>
  , &makeCurrency<RSDCurrency>
  , &makeCurrency<TNDCurrency>
  , &makeCurrency<UGXCurrency>
  , &makeCurrency<UYUCurrency>
  , &makeCurrency<UZSCurrency>
  , &makeCurrency<XOFCurrency>
  , &makeCurrency<ZMWCurrency>
};

extern "C" {
void qlFreeInts(int *p) {delArray(p);}
// Every unsigned* out-array is actually allocated as int* via qlAllocateInts (there is no
// qlAllocateUInts) -- delegate rather than duplicate so it's traced under the type it was
// really allocated as.
void qlFreeUInts(unsigned *p) {qlFreeInts(reinterpret_cast<int*>(p));}
void qlFreeDoubles(double *p) {delArray(p);}
void qlFreePointerArray(void **p) {delArray(p);}
void qlFreeStringArray(unsigned n, char **p) {
  if (!p) return;
  for (unsigned i = 0; i < n; ++i) qlFreeString(p[i]);
  delArray(p);
}
int qlNullInteger() {return Null<Integer>();}
double qlNullReal() {return Null<Real>();}
double qlEpsilon() {return QL_EPSILON;}

Currency *qlCurrency(int ccy, char **e) {
  try {
    if (ccy < 0 || ccy >= (int)std::size(ccys))
      QL_FAIL("Invalid currency index: " << ccy);
    return alloc(ccys[ccy]());
  } catch (std::exception& er) {return handleException<Currency *>(e, er);}}

void qlFreeString(char *p) {
  // The address is captured as an integer *before* the free and cast back only for printing.
  // Reading a freed pointer's value is implementation-defined ([basic.stc]/4 -- printing it is
  // the benign case, not UB), but GCC's -Wuse-after-free rejects it anyway, and a plain
  // `void *addr = p;' copy does not help: every copy of the pointer goes invalid too, and GCC
  // flags that form as well. Only the integer round trip satisfies it. Both spellings reach
  // operator<<(const void*), so the printed form stays byte-identical to every other trace
  // line. (del()/delArray() keep the plain `trace("deleted", p)' -- same implementation-defined
  // read, but after `delete' rather than free(), which GCC does not track.)
  const auto addr = reinterpret_cast<std::uintptr_t>(p);
  trace("Freeing string", reinterpret_cast<void *>(addr));
  free(p);
  trace("Freed string", reinterpret_cast<void *>(addr));
}

/* dates are passed as int = serial number of the date, the code assumes that Haskell bindings validate date */
int qlSettingsEvaluationDate() {return Settings::instance().evaluationDate().operator Date().serialNumber();}
int qlSettingsEnforceTodaysHistoricFixings() {return Settings::instance().enforcesTodaysHistoricFixings();}

void qlSettingsSetEvaluationDate(int x, char **e) {
  try {Settings::instance().evaluationDate() = qlNullableDate(x);
  } catch (std::exception& er) {handleException<void *>(e, er);}}

void qlSettingsSetEnforceTodaysHistoricFixings(int x) {Settings::instance().enforcesTodaysHistoricFixings() = x;}
int qlSettingsIncludeTodaysCashFlows() {return qlOptBool(Settings::instance().includeTodaysCashFlows());}
void qlSettingsSetIncludeTodaysCashFlows(int x) {Settings::instance().includeTodaysCashFlows() = qlOptBool(x);}
int qlSettingsIncludeReferenceDateEvents() {return Settings::instance().includeReferenceDateEvents();}
void qlSettingsSetIncludeReferenceDateEvents(int x0) {Settings::instance().includeReferenceDateEvents() = x0;}
void qlObservableSettingsDisableUpdates(int deferred) {ObservableSettings::instance().disableUpdates(deferred);}
void qlObservableSettingsEnableUpdates(char **e) {
  try {ObservableSettings::instance().enableUpdates();
  } catch (std::exception& er) {*e = tracedup(er.what());}}
int qlObservableSettingsUpdatesEnabled() {return ObservableSettings::instance().updatesEnabled();}
int qlObservableSettingsUpdatesDeferred() {return ObservableSettings::instance().updatesDeferred();}
void *qlSavedSettings() {return ret(new SavedSettingsWithObservable());}
void qlFreeSavedSettings(void *settings) {del((SavedSettingsWithObservable *)settings);}
const char *qlVersion() {return QL_VERSION;}
const char *qlBoostVersion() {return BOOST_LIB_VERSION;}

// GHC leaves the per-thread x87 control word at 53-bit precision on Windows, but Boost.Math's
// promote_double algorithms require 64-bit extended precision. Call this on each pricing thread;
// process initializers and one-shot RTS hooks cannot establish per-thread state. Use fldcw because
// MSVC documents _MCW_PC as unsupported on x64. Haskell Double arithmetic uses SSE/MXCSR and is
// unaffected. See WINDOWS.md and tools/debug/hestonslv-probe.cpp.
void qlSetExtendedPrecision() {
#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
  unsigned short cw = 0;
  __asm__ __volatile__("fnstcw %0" : "=m"(cw));
  cw = (unsigned short)((cw & ~0x0300u) | 0x0300u);
  __asm__ __volatile__("fldcw %0" : : "m"(cw));
#endif
}

void qlFreeCurrency(Currency *currency) {del(currency);}
const char *qlCurrencyName(Currency *currency) {return tracedup(arg(currency)->name().c_str());}
char* qlCurrencyCode(Currency* o) {return tracedup(arg(o)->code().c_str());}
int qlCurrencyFractionsPerUnit(Currency* o) {return arg(o)->fractionsPerUnit();}
char* qlCurrencyFractionSymbol(Currency* o) {return tracedup(arg(o)->fractionSymbol().c_str());}
int qlCurrencyNumericCode(Currency* o) {return arg(o)->numericCode();}
char* qlCurrencySymbol(Currency* o) {return tracedup(arg(o)->symbol().c_str());}
void qlFreeInterestRate(InterestRate *rate) {del(rate);}

class CustomCurrency : public Currency {
  public:
    CustomCurrency(const char* name, const char* code, int numericCode,
        const char* symbol, const char* fractionSymbol, int fractionsPerUnit,
        Rounding* rounding,
        Currency* triangulationCurrency) {
      shared_ptr<Data> data(new Data(name, code, numericCode, symbol, fractionSymbol, fractionsPerUnit,
            rounding ? *rounding : Rounding(), triangulationCurrency ? *triangulationCurrency : Currency()));
      data_ = data;
    }
};

Currency* qlCreateCurrency(char* name, char* code, int numericCode, char* symbol, char* fractionSymbol, int fractionsPerUnit, Rounding* rounding, Currency* triangulationCurrency, char **e) {
  try {
    return alloc(new CustomCurrency(arg(name), arg(code), numericCode,
          arg(symbol), arg(fractionSymbol), fractionsPerUnit,
          rounding, triangulationCurrency));
  } catch (std::exception& er) {return handleException<Currency*>(e, er);}}

ExchangeRate *qlExchangeRate(Currency *source, Currency *target, double rate, char **e) {
  try {return alloc(new ExchangeRate(*arg(source), *arg(target), rate));
  } catch (std::exception& er) {return handleException<ExchangeRate*>(e, er);}
}
void qlFreeExchangeRate(ExchangeRate *o) {del(o);}
double qlExchangeRateRate(ExchangeRate *o) {return arg(o)->rate();}
int qlExchangeRateType_(ExchangeRate *o) {return arg(o)->type();}

double qlExchangeRateExchange(ExchangeRate *o, double amount, Currency *ccy, Currency **outCcy, char **e) {
  *outCcy = 0;
  try {
    Money m = arg(o)->exchange(Money(amount, *arg(ccy)));
    *outCcy = ret(new Currency(m.currency()));
    return m.value();
  } catch (std::exception& er) {return handleException<double>(e, er);}
}

ExchangeRate *qlExchangeRateChain(ExchangeRate *r1, ExchangeRate *r2, char **e) {
  try {
    return ret(new ExchangeRate(ExchangeRate::chain(*arg(r1), *arg(r2))));
  } catch (std::exception& er) {return handleException<ExchangeRate*>(e, er);}
}

void qlExchangeRateManagerAdd(ExchangeRate *rate, int startSerial, int endSerial, char **e) {
  try {ExchangeRateManager::instance().add(*arg(rate), qlNullableDate(startSerial), qlNullableDate(endSerial));
  } catch (std::exception& er) {*e = tracedup(er.what());}
}

ExchangeRate *qlExchangeRateManagerLookup(Currency *source, Currency *target, int dateSerial, int type, char **e) {
  try {
    return ret(new ExchangeRate(ExchangeRateManager::instance().lookup(
        *arg(source), *arg(target), qlNullableDate(dateSerial), (ExchangeRate::Type)type)));
  } catch (std::exception& er) {return handleException<ExchangeRate*>(e, er);}
}

void qlExchangeRateManagerClear() {ExchangeRateManager::instance().clear();}

int qlMoneySettingsConversionType() {return Money::Settings::instance().conversionType();}
void qlMoneySettingsSetConversionType(int t) {Money::Settings::instance().conversionType() = (Money::ConversionType)t;}
Currency *qlMoneySettingsBaseCurrency(char **e) {
  try {
    const Currency &base = Money::Settings::instance().baseCurrency();
    return base.empty() ? 0 : ret(new Currency(base));
  } catch (std::exception& er) {return handleException<Currency*>(e, er);}
}
void qlMoneySettingsSetBaseCurrency(Currency *c) {Money::Settings::instance().baseCurrency() = *arg(c);}

double qlConvertToBaseCurrency(double amount, Currency *ccy, Currency **outCcy, char **e) {
  *outCcy = 0;
  try {
    const Currency &base = Money::Settings::instance().baseCurrency();
    QL_REQUIRE(!base.empty(), "no base currency set");
    Money m(amount, *arg(ccy));
    if (m.currency() != base) {
      ExchangeRate rate = ExchangeRateManager::instance().lookup(m.currency(), base);
      m = rate.exchange(m).rounded();
    }
    *outCcy = ret(new Currency(m.currency()));
    return m.value();
  } catch (std::exception& er) {return handleException<double>(e, er);}
}

InterestRate *qlInterestRate(double r, DayCounter *dc, int comp, int freq, char **e) {
  try {return alloc(new InterestRate(r, *arg(dc), (Compounding) comp, (Frequency) freq));
  } catch (std::exception& er) {return handleException<InterestRate *>(e, er);}}

// generated code
double qlInterestRateCompoundFactor1(InterestRate* o, int d1, int d2, int refStart, int refEnd, char **e) {
  try {return (arg(o))->compoundFactor(Date(d1), Date(d2), qlNullableDate(refStart), qlNullableDate(refEnd));
  } catch (std::exception& er) {return handleException<double>(e, er);}}

double qlInterestRateCompoundFactor(InterestRate* o, double t, char **e) {
  try {return (arg(o))->compoundFactor(t);
  } catch (std::exception& er) {return handleException<double>(e, er);}}

double qlInterestRateDiscountFactor1(InterestRate* o, int d1, int d2, int refStart, int refEnd, char **e) {
  try {return (arg(o))->discountFactor(Date(d1), Date(d2), qlNullableDate(refStart), qlNullableDate(refEnd));
  } catch (std::exception& er) {return handleException<double>(e, er);}}

double qlInterestRateDiscountFactor(InterestRate* o, double t, char **e) {
  try {return (arg(o))->discountFactor(t);
  } catch (std::exception& er) {return handleException<double>(e, er);}}

InterestRate* qlInterestRateEquivalentRate1(InterestRate* o, DayCounter* resultDC, int comp, int freq, int d1, int d2, int refStart, int refEnd, char **e) {
  try {return ret(new InterestRate(arg(o)->equivalentRate(*arg(resultDC), (Compounding)comp, (Frequency)freq, Date(d1), Date(d2), qlNullableDate(refStart), qlNullableDate(refEnd))));
  } catch (std::exception& er) {return handleException<InterestRate*>(e, er);}}

InterestRate* qlInterestRateEquivalentRate(InterestRate* o, int comp, int freq, double t, char **e) {
  try {return ret(new InterestRate(arg(o)->equivalentRate((Compounding)comp, (Frequency)freq, t)));
  } catch (std::exception& er) {return handleException<InterestRate*>(e, er);}}

InterestRate* qlInterestRateImpliedRate1(InterestRate* o, double compound, DayCounter* resultDC, int comp, int freq, int d1, int d2, int refStart, int refEnd, char **e) {
  try {return ret(new InterestRate(arg(o)->impliedRate(compound, *arg(resultDC), (Compounding)comp, (Frequency)freq, Date(d1), Date(d2), qlNullableDate(refStart), qlNullableDate(refEnd))));
  } catch (std::exception& er) {return handleException<InterestRate*>(e, er);}}

InterestRate* qlInterestRateImpliedRate(InterestRate* o, double compound, DayCounter* resultDC, int comp, int freq, double t, char **e) {
  try {return ret(new InterestRate(arg(o)->impliedRate(compound, *arg(resultDC), (Compounding)comp, (Frequency)freq, t)));
  } catch (std::exception& er) {return handleException<InterestRate*>(e, er);}}

Constraint* qlBoundaryConstraint(double low, double high, char **e) {
  try {return alloc(new BoundaryConstraint(low, high));
  } catch (std::exception& er) {return handleException<Constraint*>(e, er);}}
Constraint* qlCompositeConstraint(Constraint* c1, Constraint* c2, char **e) {
  try {return alloc(new CompositeConstraint(*arg(c1), *arg(c2)));
  } catch (std::exception& er) {return handleException<Constraint*>(e, er);}}
Constraint* qlNoConstraint(char **e) {
  try {return alloc(new NoConstraint());
  } catch (std::exception& er) {return handleException<Constraint*>(e, er);}}
Constraint* qlPositiveConstraint(char **e) {
  try {return alloc(new PositiveConstraint());
  } catch (std::exception& er) {return handleException<Constraint*>(e, er);}}

QlOptimizationMethod* qlLevenbergMarquardt(double epsfcn, double xtol, double gtol, int useCostFunctionsJacobian, char **e) {
  try {return ret(new QlOptimizationMethod(shared_ptr<OptimizationMethod>(alloc(new LevenbergMarquardt(epsfcn, xtol, gtol, useCostFunctionsJacobian)))));
  } catch (std::exception& er) {return handleException<QlOptimizationMethod*>(e, er);}}
QlOptimizationMethod* qlSimplex(double lambda, char **e) {
  try {return ret(new QlOptimizationMethod(shared_ptr<OptimizationMethod>(alloc(new Simplex(lambda)))));
  } catch (std::exception& er) {return handleException<QlOptimizationMethod*>(e, er);}}

QlEndCriteria* qlEndCriteria(unsigned maxIterations, unsigned maxStationaryStateIterations, double rootEpsilon, double functionEpsilon, double gradientNormEpsilon, char **e) {
  try {return ret(new QlEndCriteria(shared_ptr<EndCriteria>(alloc(new EndCriteria(maxIterations, maxStationaryStateIterations, rootEpsilon, functionEpsilon, gradientNormEpsilon)))));
  } catch (std::exception& er) {return handleException<QlEndCriteria*>(e, er);}}

void qlOptimize(double (*costFn)(double*, unsigned), unsigned x0Len, double* x0, Constraint* constraint, QlOptimizationMethod* method, QlEndCriteria* endCriteria, unsigned* outLen, double** outValues, double* outCost, int* outEndCriteriaType, char **e) {
  OutArrayResult<double> valuesResult(outLen, outValues);
  OutValue<double> costResult(outCost);
  OutValue<int> endCriteriaResult(outEndCriteriaType);
  try {
    HsCostFunction cf(costFn);
    NoConstraint noConstraint;
    Problem problem(cf, constraint ? *arg(constraint) : static_cast<Constraint&>(noConstraint), Array(x0, x0+x0Len));
    endCriteriaResult.set((int)(*arg(method))->minimize(problem, **arg(endCriteria)));
    const Array& sol = problem.currentValue();
    costResult.set(problem.functionValue());
    double *values = valuesResult.allocate((unsigned)sol.size());
    std::copy(sol.begin(), sol.end(), values);
    valuesResult.commit();
    costResult.commit();
    endCriteriaResult.commit();
  } catch (std::exception& er) {(void)handleException<int>(e, er);}}

TimeGrid* qlTimeGrid1(double end, unsigned steps, char **e) {
  try {return alloc(new TimeGrid(end, steps));
  } catch (std::exception& er) {return handleException<TimeGrid*>(e, er);}}
TimeGrid* qlTimeGrid2(unsigned x0Len, double* x0, char **e) {
  try {return alloc(new TimeGrid(x0, x0+x0Len));
  } catch (std::exception& er) {return handleException<TimeGrid*>(e, er);}}
TimeGrid* qlTimeGrid3(unsigned x0Len, double* x0, unsigned steps, char **e) {
  try {return alloc(new TimeGrid(x0, x0+x0Len, steps));
  } catch (std::exception& er) {return handleException<TimeGrid*>(e, er);}}
unsigned qlTimeGridSize(TimeGrid* t) {return arg(t)->size();}
double qlTimeGridAt(TimeGrid* t, unsigned i, char **e) {try {return arg(t)->at(i);} catch (std::exception& er) {return handleException<double>(e, er);}}
void qlTimeGridPoints(TimeGrid *t, unsigned *len, double **p, char **e) {
  try {fillVectorOut([&] {return std::vector<double>(arg(t)->begin(), t->end());}, len, p);
  } catch (std::exception& er) {(void)handleException<double*>(e, er);}}

double qlRiskStatisticsMean(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).mean();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsStandardDeviation(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).standardDeviation();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsVariance(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).variance();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsSkewness(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).skewness();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsKurtosis(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).kurtosis();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsMin(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).min();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsMax(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).max();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsSemiVariance(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).semiVariance();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsSemiDeviation(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).semiDeviation();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsDownsideVariance(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).downsideVariance();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsDownsideDeviation(unsigned n, double *xs, char **e) {
  try {return riskStats(n, xs).downsideDeviation();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsPercentile(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).percentile(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsGaussianPercentile(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).gaussianPercentile(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsValueAtRisk(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).valueAtRisk(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsGaussianValueAtRisk(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).gaussianValueAtRisk(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsExpectedShortfall(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).expectedShortfall(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsGaussianExpectedShortfall(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).gaussianExpectedShortfall(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsPotentialUpside(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).potentialUpside(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsGaussianPotentialUpside(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).gaussianPotentialUpside(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsRegret(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).regret(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsShortfall(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).shortfall(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}
double qlRiskStatisticsAverageShortfall(unsigned n, double *xs, double y, char **e) {
  try {return riskStats(n, xs).averageShortfall(y);
  } catch (std::exception& er) {return handleException<double>(e, er);}}

void qlSymmetricSchurDecomposition(unsigned rows, unsigned cols, double *m,
    unsigned *valuesLen, double **values,
    unsigned *vectorRows, unsigned *vectorCols, unsigned *vectorsLen, double **vectors, char **e) {
  // Both outputs are staged and committed together, so a failure building either leaves neither
  // array published.
  OutArrayResult<double> valueResult(valuesLen, values);
  OutValue<unsigned> rowResult(vectorRows), colResult(vectorCols);
  OutArrayResult<double> vectorResult(vectorsLen, vectors);
  try {
    SymmetricSchurDecomposition dec(qlMatrix(m, rows, cols));
    const Array& d = dec.eigenvalues();
    const Matrix& u = dec.eigenvectors();
    std::copy(d.begin(), d.end(), valueResult.allocate((unsigned)d.size()));
    std::copy(u.begin(), u.end(), vectorResult.allocate((unsigned)(u.rows() * u.columns())));
    rowResult.set((unsigned)u.rows());
    colResult.set((unsigned)u.columns());
    valueResult.commit();
    vectorResult.commit();
    rowResult.commit();
    colResult.commit();
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlPseudoSqrt(unsigned rows, unsigned cols, double *m, int salvaging,
    unsigned *outRows, unsigned *outCols, unsigned *len, double **vs, char **e) {
  try {fillMatrixOut([&] {return pseudoSqrt(qlMatrix(m, rows, cols), (SalvagingAlgorithm::Type)salvaging);},
      outRows, outCols, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlRankReducedSqrt(unsigned rows, unsigned cols, double *m, unsigned maxRank,
    double componentRetainedPercentage, int salvaging,
    unsigned *outRows, unsigned *outCols, unsigned *len, double **vs, char **e) {
  try {fillMatrixOut([&] {return rankReducedSqrt(qlMatrix(m, rows, cols), maxRank,
        componentRetainedPercentage, (SalvagingAlgorithm::Type)salvaging);},
      outRows, outCols, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlCholeskyDecomposition(unsigned rows, unsigned cols, double *m, int flexible,
    unsigned *outRows, unsigned *outCols, unsigned *len, double **vs, char **e) {
  try {fillMatrixOut([&] {return CholeskyDecomposition(qlMatrix(m, rows, cols), flexible != 0);},
      outRows, outCols, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlCholeskySolveFor(unsigned rows, unsigned cols, double *l, unsigned bLen, double *b,
    unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return CholeskySolveFor(qlMatrix(l, rows, cols), Array(b, b + bLen));}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

Rounding* qlRounding(char **e) {try {return alloc(new Rounding());} catch (std::exception& er) {return handleException<Rounding*>(e, er);}}
Rounding* qlRounding1(int precision, int type, int digit, char **e) {try {return alloc(new Rounding(precision, (Rounding::Type)type, digit));} catch (std::exception& er) {return handleException<Rounding*>(e, er);}}

QlSimpleQuote *qlSimpleQuote(double value, char **e) {try {return ret(new QlSimpleQuote(alloc(new SimpleQuote(value))));} catch (std::exception& er) {return handleException<QlSimpleQuote *>(e, er);}}
double qlQuoteValue(QlQuote *quote, char **e) {try {return (*arg(quote))->value();} catch (std::exception& er) {return handleException<double>(e, er);}}
double qlSimpleQuoteSetValue(QlSimpleQuote* o, double value, char **e) {try {return (*arg(o))->setValue(value);} catch (std::exception& er) {return handleException<double>(e, er);}}

QlQuote* qlEurodollarFuturesImpliedStdDevQuote(QlQuote* forward, QlQuote* callPrice, QlQuote* putPrice, double strike, double guess, double accuracy, unsigned maxIter, char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new EurodollarFuturesImpliedStdDevQuote(*arg(forward), *arg(callPrice), *arg(putPrice), strike, guess, accuracy, maxIter)))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlQuote* qlForwardSwapQuote(QlSwapIndex* swapIndex, QlQuote* spread, int l, int u, char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new ForwardSwapQuote(*arg(swapIndex), *arg(spread), Period(l, (TimeUnit)u))))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlQuote* qlForwardValueQuote(QlIndex* index, int fixingDate, char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new ForwardValueQuote(*arg(index), Date(fixingDate))))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlFuturesConvAdjustmentQuote* qlFuturesConvAdjustmentQuote1(QlIborIndex* index, char* immCode, QlQuote* futuresQuote, QlQuote* volatility, QlQuote* meanReversion, char **e) {
  try {return ret(new QlFuturesConvAdjustmentQuote(alloc(new FuturesConvAdjustmentQuote(*arg(index), std::string(arg(immCode)), *arg(futuresQuote), *arg(volatility), *arg(meanReversion)))));
  } catch (std::exception& er) {return handleException<QlFuturesConvAdjustmentQuote*>(e, er);}}
QlFuturesConvAdjustmentQuote* qlFuturesConvAdjustmentQuote(QlIborIndex* index, int futuresDate, QlQuote* futuresQuote, QlQuote* volatility, QlQuote* meanReversion, char **e) {
  try {return ret(new QlFuturesConvAdjustmentQuote(alloc(new FuturesConvAdjustmentQuote(*arg(index), Date(futuresDate), *arg(futuresQuote), *arg(volatility), *arg(meanReversion)))));
  } catch (std::exception& er) {return handleException<QlFuturesConvAdjustmentQuote*>(e, er);}}
void qlFreeFuturesConvAdjustmentQuote(QlFuturesConvAdjustmentQuote *o) {del(o);}
// Fresh Handle for this newly built object -- same shape as qlDeltaVolQuoteAsQuote.
QlQuote* qlFuturesConvAdjustmentQuoteAsQuote(QlFuturesConvAdjustmentQuote *o) {return ret(new QlQuote(*arg(o)));}
double qlFuturesConvAdjustmentQuoteFuturesValue(QlFuturesConvAdjustmentQuote *o, char **e) {
  try {return (*arg(o))->futuresValue();
  } catch (std::exception& er) {return handleException<double>(e, er);}}
QlQuote* qlImpliedStdDevQuote(int optionType, QlQuote* forward, QlQuote* price, double strike, double guess, double accuracy, unsigned maxIter, char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new ImpliedStdDevQuote((Option::Type)optionType, *arg(forward), *arg(price), strike, guess, accuracy, maxIter)))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlQuote* qlLastFixingQuote(QlIndex* index, char **e) {try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new LastFixingQuote(*arg(index))))));} catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
int qlQuoteIsValid(QlQuote* o, char **e) {try {return (*arg(o))->isValid();} catch (std::exception& er) {return handleException<int>(e, er);}}
QlQuote* qlDerivedQuote(int op, QlQuote* element, double operand, char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new OpDerivedQuote(*arg(element), QuoteUnaryOp{op, operand})))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlQuote* qlCompositeQuote(int op, QlQuote* element1, QlQuote* element2, char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new OpCompositeQuote(*arg(element1), *arg(element2), QuoteBinaryOp{op})))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlQuote* qlMultiCompositeQuote(int op, unsigned elementsLen, QlQuote** elements, char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new OpMultiCompositeQuote(qlHandleVector(elements, elementsLen), QuoteArrayOp{op})))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}

QlQuote* qlDerivedQuoteFromFunction(QlQuote* element, double (*fn)(double), char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new HsDerivedQuote(*arg(element), fn)))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlQuote* qlCompositeQuoteFromFunction(QlQuote* element1, QlQuote* element2, double (*fn)(double, double), char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new HsCompositeQuote(*arg(element1), *arg(element2), fn)))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}
QlQuote* qlMultiCompositeQuoteFromFunction(unsigned elementsLen, QlQuote** elements, double (*fn)(const double*, unsigned), char **e) {
  try {return ret(new QlQuote(shared_ptr<Quote>(alloc(new HsMultiCompositeQuote(qlHandleVector(elements, elementsLen), HsArrayFun{fn})))));
  } catch (std::exception& er) {return handleException<QlQuote*>(e, er);}}

// A relinkable handle, empty when `initial` is null -- mirrors qlRelinkableYieldTermStructure
// in cbits/qlTermStructure.cpp; see its comments for the rationale.
QlRelinkableQuote* qlRelinkableQuote(QlQuote *initial, char **e) {
  try {return ret(initial ? new QlRelinkableQuote(handlePtr(arg(initial)))
                          : new QlRelinkableQuote());
  } catch (std::exception& er) {return handleException<QlRelinkableQuote*>(e, er);}}
void qlFreeRelinkableQuote(QlRelinkableQuote *o) {del(o);}
void qlRelinkableQuoteLinkTo(QlRelinkableQuote *o, QlQuote *c, char **e) {
  try {arg(o)->linkTo(handlePtr(arg(c)));} catch (std::exception& er) {(void)handleException<void *>(e, er);}}
// The hierarchy upcast. Copy-constructing Handle<Quote> from RelinkableHandle<Quote> is the
// same T, so link_ is shared and relinking through the original still reaches everything built
// on the upcast copy.
QlQuote* qlRelinkableQuoteAsQuote(QlRelinkableQuote *o) {return ret(new QlQuote(*arg(o)));}
void qlFreeEndCriteria(QlEndCriteria *o) {del(o);}
double qlInterestRateRate(InterestRate* o) {return arg(o)->rate();}
void qlFreeConstraint(Constraint *o) {del(o);}
void qlFreeOptimizationMethod(QlOptimizationMethod *o) {del(o);}
void qlFreeTimeGrid(TimeGrid *o) {del(o);}
void qlFreeRounding(Rounding *o) {del(o);}
double qlRound(Rounding *r, double val) {return (*r)(val);}
void qlFreeQuote(QlQuote *quote) {del(quote);}
void qlFreeSimpleQuote(QlSimpleQuote *o) {del(o);}
QlQuote* qlSimpleQuoteAsQuote(QlSimpleQuote *o) {return ret(new QlQuote(*arg(o)));}
QlDeltaVolQuote *qlDeltaVolQuote1(double delta, QlQuote *vol, double maturity, int deltaType, char **e) {
  try {return ret(new QlDeltaVolQuote(alloc(new DeltaVolQuote(delta, *arg(vol), maturity, (DeltaVolQuote::DeltaType)deltaType))));
  } catch (std::exception& er) {return handleException<QlDeltaVolQuote*>(e, er);}}
QlDeltaVolQuote *qlDeltaVolQuote2(QlQuote *vol, int deltaType, double maturity, int atmType, char **e) {
  try {return ret(new QlDeltaVolQuote(alloc(new DeltaVolQuote(*arg(vol), (DeltaVolQuote::DeltaType)deltaType, maturity, (DeltaVolQuote::AtmType)atmType))));
  } catch (std::exception& er) {return handleException<QlDeltaVolQuote*>(e, er);}}
void qlFreeDeltaVolQuote(QlDeltaVolQuote *o) {del(o);}
QlQuote* qlDeltaVolQuoteAsQuote(QlDeltaVolQuote *o) {return ret(new QlQuote(*arg(o)));}

int qlMinDateSerialNumber() {return Date::minDate().serialNumber();}
int qlMaxDateSerialNumber() {return Date::maxDate().serialNumber();}
int qlMinYear() {return Date::minDate().year();}
int qlMinMonth() {return Date::minDate().month();}
int qlMinDay() {return Date::minDate().dayOfMonth();}
int qlWeekday(int date) {return Date(date).weekday();}
int qlDateDayOfYear(int o) {return Date(o).dayOfYear();}
int qlDateEndOfMonth(int d) {return Date::endOfMonth(Date(d)).serialNumber();}
int qlDateIsEndOfMonth(int d) {return Date::isEndOfMonth(Date(d));}
int qlDateNextWeekday(int d, int w) {return Date::nextWeekday(Date(d), (Weekday)w).serialNumber();}
// Needs an error channel where its Date-taking siblings above do not: `n' is a caller-supplied
// count, not a date, so no Haskell-side marshaller constrains it, and Date::nthWeekday requires
// 0 < n < 6.
int qlDateNthWeekday(unsigned n, int w, int m, int y, char **e) {
  try {return Date::nthWeekday(n, (Weekday)w, (Month)m, y).serialNumber();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlIMMIsIMMcode(char* in, int mainCycle) {return IMM::isIMMcode(std::string(arg(in)), mainCycle);}
int qlIMMIsIMMdate(int d, int mainCycle) {return IMM::isIMMdate(Date(d), mainCycle);}
char* qlIMMNextCode(int d, int mainCycle) {return tracedup(IMM::nextCode(Date(d), mainCycle).c_str());}
int qlIMMNextDate(int d, int mainCycle) {return IMM::nextDate(Date(d), mainCycle).serialNumber();}

char* qlIMMCode(int immDate, char **e) {try {return tracedup((IMM::code(Date(immDate))).c_str());} catch (std::exception& er) {return handleException<char*>(e, er);}}
int qlIMMDate(char* immCode, int referenceDate, char **e) {
  try {return (IMM::date(std::string(immCode), Date(referenceDate))).serialNumber();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
char* qlIMMNextCode1(char* immCode, int mainCycle, int referenceDate, char **e) {
  try {return tracedup(IMM::nextCode(std::string(arg(immCode)), mainCycle, Date(referenceDate)).c_str());
  } catch (std::exception& er) {return handleException<char*>(e, er);}}

int qlIMMNextDate1(char* immCode, int mainCycle, int referenceDate, char **e) {try {return (IMM::nextDate(std::string(arg(immCode)), mainCycle, Date(referenceDate))).serialNumber();} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlAddPeriod(int d, int n, int u, char **e) {try {return (Date(d) + Period(n, (TimeUnit)u)).serialNumber();} catch (std::exception& er) {return handleException<int>(e, er);}}
void qlECBAddDate(int d, char **e) {try {ECB::addDate(Date(d));} catch (std::exception& er) {(void)handleException<int>(e, er);}}
char* qlECBCode(int ecbDate, char **e) {try {return tracedup((ECB::code(Date(ecbDate))).c_str());} catch (std::exception& er) {return handleException<char*>(e, er);}}
int qlECBDate1(char* ecbCode, int referenceDate, char **e) {try {return (ECB::date(std::string(arg(ecbCode)), qlNullableDate(referenceDate))).serialNumber();} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlECBDate(int m, int y, char **e) {try {return (ECB::date((Month)m, y)).serialNumber();} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlECBIsECBcode(char* in, char **e) {try {return ECB::isECBcode(arg(in));} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlECBIsECBdate(int d, char **e) {try {return ECB::isECBdate(Date(d));} catch (std::exception& er) {return handleException<int>(e, er);}}
void qlECBKnownDates(unsigned *count, int **ds, char **e) {
  OutArrayResult<int> result(count, ds);
  try { const std::set<Date> &dates = ECB::knownDates(); int *out = result.allocate((unsigned)dates.size());
    std::transform(dates.begin(), dates.end(), out, std::mem_fn(&Date::serialNumber));
    result.commit();
  } catch (std::exception& er) {(void)handleException<int>(e, er);}}
char* qlECBNextCode1(char* ecbCode, char **e) {try {return tracedup((ECB::nextCode(std::string(arg(ecbCode)))).c_str());} catch (std::exception& er) {return handleException<char*>(e, er);}}
char* qlECBNextCode(int d, char **e) {try {return tracedup((ECB::nextCode(qlNullableDate(d))).c_str());} catch (std::exception& er) {return handleException<char*>(e, er);}}
int qlECBNextDate1(char* ecbCode, int referenceDate, char **e) {
  try {return (ECB::nextDate(std::string(arg(ecbCode)), qlNullableDate(referenceDate))).serialNumber();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlECBNextDate(int d, char **e) {try {return (ECB::nextDate(qlNullableDate(d))).serialNumber();} catch (std::exception& er) {return handleException<int>(e, er);}}
void qlECBNextDates1(char* ecbCode, int referenceDate, unsigned *count, int **ds, char **e) {
  OutArrayResult<int> result(count, ds);
  try {const std::vector<Date> &dates = ECB::nextDates(ecbCode, qlNullableDate(referenceDate));
    int *out = result.allocate((unsigned)dates.size());
    std::transform(dates.begin(), dates.end(), out, std::mem_fn(&Date::serialNumber));
    result.commit();
  } catch (std::exception& er) {(void)handleException<int*>(e, er);}}
void qlECBNextDates(int d, unsigned *count, int **ds, char **e) {
  OutArrayResult<int> result(count, ds);
  try {const std::vector<Date> &dates = ECB::nextDates(qlNullableDate(d));
    int *out = result.allocate((unsigned)dates.size());
    std::transform(dates.begin(), dates.end(), out, std::mem_fn(&Date::serialNumber));
    result.commit();
  } catch (std::exception& er) {(void)handleException<int*>(e, er);}}
void qlECBRemoveDate(int d, char **e) {try {ECB::removeDate(Date(d));} catch (std::exception& er) {(void)handleException<int>(e, er);}}

const char *qlCalendarName(Calendar *calendar) {std::string name = arg(calendar)->name(); return tracedup(name.c_str());}
// must match with the order of qlEnumObjects.h:CalendarCountry
static const makeCal calendars[] = {
  &makeCalendar<Argentina>
  , &makeMarketCalendar<Australia>
  , &makeMarketCalendar<Austria>
  , &makeCalendar<Botswana>
  , &makeMarketCalendar<Brazil>
  , &makeMarketCalendar<Canada>
  , &makeMarketCalendar<China>
  , &makeCalendar<CzechRepublic>
  , &makeCalendar<Denmark>
  , &makeCalendar<Finland>
  , &makeMarketCalendar<France>
  , &makeMarketCalendar<Germany>
  , &makeCalendar<HongKong>
  , &makeCalendar<Hungary>
  , &makeCalendar<Iceland>
  , &makeCalendar<India>
  , &makeMarketCalendar<Indonesia>
  , &makeMarketCalendar<Israel>
  , &makeMarketCalendar<Italy>
  , &makeCalendar<Japan>
  , &makeCalendar<Mexico>
  , &makeMarketCalendar<NewZealand>
  , &makeCalendar<Norway>
  , &makeCalendar<NullCalendar>
  , &makeMarketCalendar<Poland>
  , &makeMarketCalendar<Romania>
  , &makeMarketCalendar<Russia>
  , &makeCalendar<SaudiArabia>
  , &makeCalendar<Singapore>
  , &makeCalendar<Slovakia>
  , &makeCalendar<SouthAfrica>
  , &makeMarketCalendar<SouthKorea>
  , &makeCalendar<Sweden>
  , &makeCalendar<Switzerland>
  , &makeCalendar<Taiwan>
  , &makeCalendar<TARGET>
  , &makeCalendar<Thailand>
  , &makeCalendar<Turkey>
  , &makeCalendar<Ukraine>
  , &makeMarketCalendar<UnitedKingdom>
  , &makeMarketCalendar<UnitedStates>
  , &makeCalendar<WeekendsOnly>
  , &makeCalendar<Chile>
  , &makeCalendar<Croatia>
  , &makeCalendar<Malta>
  , &makeCalendar<Montenegro>
  , &makeCalendar<NorthMacedonia>
  , &makeCalendar<Serbia>
  , &makeCalendar<Slovenia>
  , &makeCalendar<Uzbekistan>
};

Calendar *qlCalendar(int country, int market, char **e) {
  try {
    if (country < 0 || country >= (int)std::size(calendars))
      QL_FAIL("Invalid country index: " << country);
    return alloc(calendars[country](market));
  } catch (std::exception& er) {return handleException<Calendar *>(e, er);}}

int qlCalendarAdjust(Calendar *c, int date, int conv, char **e) {
  try {return arg(c)->adjust(Date(date), (BusinessDayConvention) conv).serialNumber();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlCalendarAdvance(Calendar *c, int date, int n, int unit, int conv, int eom, char **e) {
  try {return arg(c)->advance(Date(date), n, (TimeUnit) unit,(BusinessDayConvention) conv, eom).serialNumber();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
void qlCalendarAddHoliday(Calendar* o, int x0, char **e) {try {arg(o)->addHoliday(Date(x0));} catch (std::exception& er) {(void)handleException<int>(e, er);}}

int qlCalendarBusinessDaysBetween(Calendar* o, int from, int to, int includeFirst, int includeLast, char **e) {
  try {return arg(o)->businessDaysBetween(Date(from), Date(to), includeFirst, includeLast);
  } catch (std::exception& er) {return handleException<int>(e, er);}}

int qlCalendarEndOfMonth(Calendar* o, int d, char **e) {try {return (arg(o)->endOfMonth(Date(d))).serialNumber();} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlCalendarIsBusinessDay(Calendar* o, int d, char **e) {try {return arg(o)->isBusinessDay(Date(d));} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlCalendarIsEndOfMonth(Calendar* o, int d, char **e) {try {return arg(o)->isEndOfMonth(Date(d));} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlCalendarIsHoliday(Calendar* o, int d, char **e) {try {return arg(o)->isHoliday(Date(d));} catch (std::exception& er) {return handleException<int>(e, er);}}
int qlCalendarIsWeekend(Calendar* o, int w, char **e) {try {return arg(o)->isWeekend((Weekday) w);} catch (std::exception& er) {return handleException<int>(e, er);}}
void qlCalendarRemoveHoliday(Calendar* o, int x0, char **e) {try {arg(o)->removeHoliday(Date(x0));} catch (std::exception& er) {(void)handleException<int>(e, er);}}

Calendar* qlBespokeCalendar(char* name, unsigned len, int *weekends, char **e) {
  try {
    // BespokeCalendar keeps its own extra shared_ptr member (bespokeImpl_,
    // aliased to the same control block as the inherited impl_) alongside
    // Calendar's. qlFreeCalendar deletes through a bare Calendar*, and
    // Calendar has no virtual destructor -- deleting a *BespokeCalendar
    // through Calendar* would only run ~Calendar(), leaking bespokeImpl_'s
    // refcount share and the Impl object with it. So finish building it here
    // as a BespokeCalendar (needs addWeekend, only on that type), then heap-
    // allocate a plain Calendar sliced from it: same underlying Impl control
    // block (Calendar's copy ctor just copies impl_), but now the object
    // qlFreeCalendar deletes really is a Calendar, so slicing never happens.
    BespokeCalendar cal{std::string(name)};
    for (unsigned i = 0; i < len; i++)
      cal.addWeekend((Weekday)weekends[i]);
    return ret(new Calendar(cal));
  } catch (std::exception& er) {return handleException<Calendar*>(e, er);}}

Calendar* qlJointCalendar4(Calendar* x_1, Calendar* x0, Calendar* x1, Calendar* x2, int x3, char **e) {
  try {return allocAs<Calendar>(new JointCalendar(*arg(x_1), *arg(x0), *arg(x1), *arg(x2), (JointCalendarRule)x3));
  } catch (std::exception& er) {return handleException<Calendar*>(e, er);}}
Calendar* qlJointCalendar3(Calendar* x_1, Calendar* x0, Calendar* x1, int x2, char **e) {
  try {return allocAs<Calendar>(new JointCalendar(*arg(x_1), *arg(x0), *arg(x1), (JointCalendarRule)x2));
  } catch (std::exception& er) {return handleException<Calendar*>(e, er);}}
Calendar* qlJointCalendar2(Calendar* x_1, Calendar* x0, int x1, char **e) {
  try {return allocAs<Calendar>(new JointCalendar(*arg(x_1), *arg(x0), (JointCalendarRule)x1));
  } catch (std::exception& er) {return handleException<Calendar*>(e, er);}}
void qlCalendarHolidayList(Calendar* calendar, int from, int to, int includeWeekEnds, unsigned *len, int **days, char **e) {
  OutArrayResult<int> result(len, days);
  try {const std::vector<Date> dates = arg(calendar)->holidayList(Date(from), Date(to), includeWeekEnds);
    int *out = result.allocate((unsigned)dates.size());
    for (size_t i = 0; i < dates.size(); ++i)
      out[i] = dates[i].serialNumber();
    result.commit();
  } catch (std::exception& er) {(void)handleException<int*>(e, er);}}
Schedule *qlSchedule1(unsigned len, int *dates, Calendar *cal, int conv, int termConv, int tenorLen, int tenorUnit, int rule, int eom, char **e) {
  try {std::vector<Date> d; d.reserve(len);
    for (unsigned i = 0; i < len; ++i)
      d.push_back(Date(dates[i]));
    return alloc(new Schedule(d, *arg(cal), (BusinessDayConvention) conv,
      qlOptBusinessDayConvention(termConv),
      tenorUnit < 0 ? ext::optional<Period>() : ext::optional<Period>(Period(tenorLen, (TimeUnit)tenorUnit)),
      rule < 0 ? ext::optional<DateGeneration::Rule>() : ext::optional<DateGeneration::Rule>((DateGeneration::Rule)rule),
      qlOptBool(eom)));
  } catch (std::exception& er) {return handleException<Schedule *>(e, er);}}
Schedule *qlSchedule(int eff, int term, int l, int u, Calendar *cal, int conv, int termConv, int rule, int eom, int first, int nextToLast, char **e) {
  try {return alloc(new Schedule(qlNullableDate(eff), Date(term), Period(l, (TimeUnit)u), *arg(cal),
        (BusinessDayConvention) conv, (BusinessDayConvention) termConv, (DateGeneration::Rule) rule,
        eom, qlNullableDate(first), qlNullableDate(nextToLast)));
  } catch (std::exception& er) {return handleException<Schedule *>(e, er);}}
Schedule *qlScheduleUntil(Schedule *sched, int date, char **e) {
  try {return alloc(new Schedule(arg(sched)->until(Date(date))));
  } catch (std::exception& er) {return handleException<Schedule *>(e, er);}}
void qlScheduleDates(Schedule *sched, unsigned *count, int **days, char **e) {
  OutArrayResult<int> result(count, days);
  try {
    const std::vector<Date> &dates = arg(sched)->dates();
    int *out = result.allocate((unsigned)dates.size());
    for (size_t i = 0; i < dates.size(); ++i)
      out[i] = dates[i].serialNumber();
    result.commit();
  } catch (std::exception& er) {*e = tracedup(er.what());}
}

int qlPeriodFromFrequency1(int freq, int *u, char **e) {
  try {Period p((Frequency) freq); *u = p.units(); return p.length();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlPeriodToFrequency1(int l, int u, char **e) {
  try {return Period(l, (TimeUnit)u).frequency();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlPeriodParserParse1(char* str, int* u, char **e) {
  try {const Period &p = (PeriodParser::parse(std::string(arg(str)))); *u = p.units(); return p.length();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlPeriodAdd1(int n1, int u1, int n2, int u2, int *u, char **e) {
  try {Period p = Period(n1, (TimeUnit)u1) + Period(n2, (TimeUnit)u2); *u = p.units(); return p.length();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlPeriodDivide1(int n1, int u1, int n, int *u, char **e) {
  try {Period p = Period(n1, (TimeUnit)u1)/n; *u = p.units(); return p.length();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlPeriodNormalize1(int n1, int u1, int *u, char **e) {
  try {Period p(n1, (TimeUnit)u1); p.normalize(); *u = p.units(); return p.length();
  } catch (std::exception& er) {return handleException<int>(e, er);}}
int qlPeriodsLT1(int n1, int u1, int n2, int u2, char **e) {
  try {Period p1(n1, (TimeUnit)u1); Period p2(n2, (TimeUnit)u2); return p1 < p2;
  } catch (std::exception& er) {return handleException<int>(e, er);}}


// must match with the order of qlEnumObjects.h:DayCounterType
static const makeDc dayCounters[] = {
  &makeFlagDayCounter<Actual360>
  , &makeDayCounter<Actual364>
  , &makeConvDayCounter<Actual365Fixed>
  , &makeConvDayCounter<ActualActual>
  , &makeDayCounter<OneDayCounter>
  , &makeDayCounter<SimpleDayCounter>
  , &makeConvDayCounter<Thirty360>
  , &makeDayCounter<Thirty365>
  , &makeFlagDayCounter<Actual36525>
  , &makeFlagDayCounter<Actual366>
};

DayCounter *qlDayCounter(int type, int convention, char **e) {
  try {
    if (type < 0 || type >= (int)std::size(dayCounters))
      QL_FAIL("Invalid DayCounter type: " << type);
    return alloc(dayCounters[type](convention));
  } catch (std::exception& er) {return handleException<DayCounter *>(e, er);}}

DayCounter *qlDayCounterBusiness252(Calendar *cal, char **e) {try {return allocAs<DayCounter>(new Business252(*arg(cal)));} catch (std::exception& er) {return handleException<DayCounter *>(e, er);}}
DayCounter *qlDayCounterActualActualBond(Schedule *schedule, char **e) {try {return allocAs<DayCounter>(new ActualActual(ActualActual::Bond, *arg(schedule)));} catch (std::exception& er) {return handleException<DayCounter *>(e, er);}}
DayCounter *qlDayCounterActualActualISMA(Schedule *schedule, char **e) {try {return allocAs<DayCounter>(new ActualActual(ActualActual::ISMA, *arg(schedule)));} catch (std::exception& er) {return handleException<DayCounter *>(e, er);}}
void qlFreeCalendar(Calendar *calendar) {del(calendar);}
void qlFreeSchedule(Schedule *s) {del(s);}
void  qlFreeDayCounter(DayCounter *counter) {del(counter);}
const char *qlDayCounterName(DayCounter *counter) {std::string name = arg(counter)->name(); return tracedup(name.c_str());}
int qlDayCounterDayCount(DayCounter* o, int x0, int x1) {return arg(o)->dayCount(Date(x0), Date(x1));}

double qlDayCounterYearFraction(DayCounter* o, int x0, int x1, int refPeriodStart, int refPeriodEnd, char **e) {
  try {return arg(o)->yearFraction(Date(x0), Date(x1), qlNullableDate(refPeriodStart), qlNullableDate(refPeriodEnd));
  } catch (std::exception& er) {return handleException<double>(e, er);}}

/* CommodityType */

CommodityType *qlCommodityType(char *code, char *name, char **e) {
  // commoditytype.hpp's declaration names its params (code, name), but the out-of-line
  // definition in commoditytype.cpp takes (name, code) -- and that's what actually executes.
  try {return alloc(new CommodityType(arg(name), arg(code)));
  } catch (std::exception& er) {return handleException<CommodityType*>(e, er);}}

CommodityType *qlNullCommodityType(char **e) {
  try {return alloc(new CommodityType(NullCommodityType()));
  } catch (std::exception& er) {return handleException<CommodityType*>(e, er);}}

void qlFreeCommodityType(CommodityType *o) {del(o);}
char *qlCommodityTypeCode(CommodityType *o) {return tracedup(arg(o)->code().c_str());}
char *qlCommodityTypeName(CommodityType *o) {return tracedup(arg(o)->name().c_str());}
int qlCommodityTypeEmpty(CommodityType *o) {return arg(o)->empty();}

/* UnitOfMeasure */

UnitOfMeasure *qlUnitOfMeasure(char *name, char *code, int unitType, char **e) {
  try {return alloc(new UnitOfMeasure(arg(name), arg(code), (UnitOfMeasure::Type)unitType));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}

void qlFreeUnitOfMeasure(UnitOfMeasure *o) {del(o);}
char *qlUnitOfMeasureName(UnitOfMeasure *o) {return tracedup(arg(o)->name().c_str());}
char *qlUnitOfMeasureCode(UnitOfMeasure *o) {return tracedup(arg(o)->code().c_str());}
int qlUnitOfMeasureUnitType(UnitOfMeasure *o) {return arg(o)->unitType();}
int qlUnitOfMeasureEmpty(UnitOfMeasure *o) {return arg(o)->empty();}

UnitOfMeasure *qlLotUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(LotUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlBarrelUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(BarrelUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlMTUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(MTUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlMBUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(MBUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlGallonUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(GallonUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlLitreUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(LitreUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlKilolitreUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(KilolitreUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlTokyoKilolitreUnitOfMeasure(char **e) {
  try {return alloc(new UnitOfMeasure(TokyoKilolitreUnitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}

/* PaymentTerm */

PaymentTerm *qlPaymentTerm(char *name, int eventType, int offsetDays, Calendar *calendar, char **e) {
  try {return alloc(new PaymentTerm(arg(name), (PaymentTerm::EventType)eventType, offsetDays, *arg(calendar)));
  } catch (std::exception& er) {return handleException<PaymentTerm*>(e, er);}}

void qlFreePaymentTerm(PaymentTerm *o) {del(o);}
char *qlPaymentTermName(PaymentTerm *o) {return tracedup(arg(o)->name().c_str());}
int qlPaymentTermEventType_(PaymentTerm *o) {return arg(o)->eventType();}
int qlPaymentTermOffsetDays(PaymentTerm *o) {return arg(o)->offsetDays();}
Calendar *qlPaymentTermCalendar(PaymentTerm *o, char **e) {
  try {return ret(new Calendar(arg(o)->calendar()));
  } catch (std::exception& er) {return handleException<Calendar*>(e, er);}}
int qlPaymentTermEmpty(PaymentTerm *o) {return arg(o)->empty();}

int qlPaymentTermGetPaymentDate(PaymentTerm *o, int date, char **e) {
  try {return arg(o)->getPaymentDate(qlNullableDate(date)).serialNumber();
  } catch (std::exception& er) {return handleException<int>(e, er);}}

/* Quantity -- see qlCommodity.h on why this is three flat arguments, not one tuple. */

double qlQuantityRoundedAmount(UnitOfMeasure *uom, double amount) {
  return arg(uom)->rounding()(amount);}

int qlQuantityClose(CommodityType *ct1, UnitOfMeasure *uom1, double amount1,
                    CommodityType *ct2, UnitOfMeasure *uom2, double amount2, int n, char **e) {
  try {return close(Quantity(*arg(ct1), *arg(uom1), amount1),
                    Quantity(*arg(ct2), *arg(uom2), amount2), n);
  } catch (std::exception& er) {return handleException<int>(e, er);}}

int qlQuantityCloseEnough(CommodityType *ct1, UnitOfMeasure *uom1, double amount1,
                          CommodityType *ct2, UnitOfMeasure *uom2, double amount2, int n, char **e) {
  try {return close_enough(Quantity(*arg(ct1), *arg(uom1), amount1),
                           Quantity(*arg(ct2), *arg(uom2), amount2), n);
  } catch (std::exception& er) {return handleException<int>(e, er);}}

/* UnitOfMeasureConversion */

UnitOfMeasureConversion *qlUnitOfMeasureConversion(CommodityType *commodityType, UnitOfMeasure *source,
                                                   UnitOfMeasure *target, double conversionFactor, char **e) {
  try {return alloc(new UnitOfMeasureConversion(*arg(commodityType), *arg(source), *arg(target), conversionFactor));
  } catch (std::exception& er) {return handleException<UnitOfMeasureConversion*>(e, er);}}

void qlFreeUnitOfMeasureConversion(UnitOfMeasureConversion *o) {del(o);}
UnitOfMeasure *qlUnitOfMeasureConversionSource(UnitOfMeasureConversion *o, char **e) {
  try {return ret(new UnitOfMeasure(arg(o)->source()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
UnitOfMeasure *qlUnitOfMeasureConversionTarget(UnitOfMeasureConversion *o, char **e) {
  try {return ret(new UnitOfMeasure(arg(o)->target()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
CommodityType *qlUnitOfMeasureConversionCommodityType(UnitOfMeasureConversion *o, char **e) {
  try {return ret(new CommodityType(arg(o)->commodityType()));
  } catch (std::exception& er) {return handleException<CommodityType*>(e, er);}}
int qlUnitOfMeasureConversionType_(UnitOfMeasureConversion *o) {return arg(o)->type();}
double qlUnitOfMeasureConversionFactor(UnitOfMeasureConversion *o) {return arg(o)->conversionFactor();}
char *qlUnitOfMeasureConversionCode(UnitOfMeasureConversion *o) {return tracedup(arg(o)->code().c_str());}

double qlUnitOfMeasureConversionConvert(UnitOfMeasureConversion *o, CommodityType *ct, UnitOfMeasure *uom,
                                        double amount, CommodityType **outCt, UnitOfMeasure **outUom, char **e) {
  *outCt = 0; *outUom = 0;
  try {
    Quantity r = arg(o)->convert(Quantity(*arg(ct), *arg(uom), amount));
    // unique_ptr until both allocations have succeeded -- same shape as qlEnergyCommodityQuantity
    // (qlInstrument.cpp): a throw from the second releases the first with no cleanup in the catch,
    // and ret() runs only on the pointers actually handed out.
    std::unique_ptr<CommodityType> ct2(new CommodityType(r.commodityType()));
    std::unique_ptr<UnitOfMeasure> uom2(new UnitOfMeasure(r.unitOfMeasure()));
    *outCt = ret(ct2.release());
    *outUom = ret(uom2.release());
    return r.amount();
  } catch (std::exception& er) {
    return handleException<double>(e, er);
  }}

UnitOfMeasureConversion *qlUnitOfMeasureConversionChain(UnitOfMeasureConversion *r1, UnitOfMeasureConversion *r2, char **e) {
  try {return alloc(new UnitOfMeasureConversion(UnitOfMeasureConversion::chain(*arg(r1), *arg(r2))));
  } catch (std::exception& er) {return handleException<UnitOfMeasureConversion*>(e, er);}}

/* UnitOfMeasureConversionManager */

UnitOfMeasureConversion *qlUnitOfMeasureConversionManagerLookup(
    CommodityType *commodityType, UnitOfMeasure *source, UnitOfMeasure *target, int type, char **e) {
  try {return alloc(new UnitOfMeasureConversion(UnitOfMeasureConversionManager::instance().lookup(
      *arg(commodityType), *arg(source), *arg(target), (UnitOfMeasureConversion::Type)type)));
  } catch (std::exception& er) {return handleException<UnitOfMeasureConversion*>(e, er);}}

void qlUnitOfMeasureConversionManagerAdd(UnitOfMeasureConversion *c) {
  UnitOfMeasureConversionManager::instance().add(*arg(c));}

void qlUnitOfMeasureConversionManagerClear() {UnitOfMeasureConversionManager::instance().clear();}

/* CommoditySettings */

Currency *qlCommoditySettingsCurrency(char **e) {
  try {return ret(new Currency(CommoditySettings::instance().currency()));
  } catch (std::exception& er) {return handleException<Currency*>(e, er);}}
void qlCommoditySettingsSetCurrency(Currency *c) {CommoditySettings::instance().currency() = *arg(c);}
UnitOfMeasure *qlCommoditySettingsUnitOfMeasure(char **e) {
  try {return ret(new UnitOfMeasure(CommoditySettings::instance().unitOfMeasure()));
  } catch (std::exception& er) {return handleException<UnitOfMeasure*>(e, er);}}
void qlCommoditySettingsSetUnitOfMeasure(UnitOfMeasure *u) {CommoditySettings::instance().unitOfMeasure() = *arg(u);}

/* HistoricalIndexAnalysis */

namespace QuantLib {
  // Index-generic counterpart of upstream HistoricalRatesAnalysis, with the same result shape.
  class HistoricalIndexAnalysis {
    public:
      HistoricalIndexAnalysis(shared_ptr<SequenceStatistics> stats,
                               std::vector<Date> skippedDates,
                               std::vector<std::string> skippedDatesErrorMessage)
        : stats_(std::move(stats)), skippedDates_(std::move(skippedDates)),
          skippedDatesErrorMessage_(std::move(skippedDatesErrorMessage)) {}
      const shared_ptr<SequenceStatistics>& stats() const {return stats_;}
      const std::vector<Date>& skippedDates() const {return skippedDates_;}
      const std::vector<std::string>& skippedDatesErrorMessage() const {return skippedDatesErrorMessage_;}
    private:
      shared_ptr<SequenceStatistics> stats_;
      std::vector<Date> skippedDates_;
      std::vector<std::string> skippedDatesErrorMessage_;
  };
}

QlHistoricalIndexAnalysis *qlHistoricalIndexAnalysis(int startDate, int endDate,
    int stepLen, int stepUnit, unsigned indexesLen, QlIndex **indexes, char **e) {
  try {
    Size nIdx = indexesLen;
    shared_ptr<SequenceStatistics> stats = ext::make_shared<SequenceStatistics>(nIdx);
    std::vector<Date> skippedDates;
    std::vector<std::string> skippedDatesErrorMessage;

    // Follow upstream historicalratesanalysis.cpp over the generic Index interface.
    std::vector<Real> sample(nIdx), prevSample(nIdx), sampleDiff(nIdx);
    Calendar cal = (*arg(indexes[0]))->fixingCalendar();
    Date currentDate = cal.advance(Date(startDate), 1*Days, Following);
    bool isFirst = true;
    for (; currentDate <= Date(endDate);
        currentDate = cal.advance(currentDate, Period(stepLen, (TimeUnit)stepUnit), Following)) {
      try {
        for (Size i = 0; i < nIdx; ++i)
          sample[i] = (*arg(indexes[i]))->fixing(currentDate, false);
      } catch (std::exception& er) {
        skippedDates.push_back(currentDate);
        skippedDatesErrorMessage.emplace_back(er.what());
        continue;
      }
      if (!isFirst) {
        for (Size i = 0; i < nIdx; ++i)
          sampleDiff[i] = sample[i]/prevSample[i] - 1.0;
        stats->add(sampleDiff.begin(), sampleDiff.end());
      } else isFirst = false;
      std::swap(prevSample, sample);
    }

    return ret(new QlHistoricalIndexAnalysis(alloc(new HistoricalIndexAnalysis(
        stats, skippedDates, skippedDatesErrorMessage))));
  } catch (std::exception& er) {return handleException<QlHistoricalIndexAnalysis*>(e, er);}}

void qlFreeHistoricalIndexAnalysis(QlHistoricalIndexAnalysis *o) {del(o);}

void qlHistoricalIndexAnalysisSkippedDates(QlHistoricalIndexAnalysis *o, unsigned *count, int **days, char **e) {
  OutArrayResult<int> result(count, days);
  try {
    const std::vector<Date> &dates = (*arg(o))->skippedDates();
    int *out = result.allocate((unsigned)dates.size());
    for (unsigned i = 0; i < dates.size(); ++i) out[i] = dates[i].serialNumber();
    result.commit();
  } catch (std::exception& er) {*e = tracedup(er.what());}
}

void qlHistoricalIndexAnalysisSkippedDatesErrorMessage(QlHistoricalIndexAnalysis *o, unsigned *count, char ***msgs, char **e) {
  OutStringArrayResult result(count, msgs);
  try {
    const std::vector<std::string> &m = (*arg(o))->skippedDatesErrorMessage();
    const unsigned n = (unsigned)m.size();
    char **ms = result.allocate(n);
    for (unsigned i = 0; i < n; ++i) ms[i] = tracedup(m[i].c_str());
    result.commit();
  } catch (std::exception& er) {*e = tracedup(er.what());}
}

void qlHistoricalIndexAnalysisMean(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->mean();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisStandardDeviation(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->standardDeviation();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisSkewness(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->skewness();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisKurtosis(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->kurtosis();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisMin(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->min();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisMax(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->max();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisSemiVariance(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->semiVariance();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisSemiDeviation(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->semiDeviation();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisDownsideVariance(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->downsideVariance();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisDownsideDeviation(QlHistoricalIndexAnalysis *o, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->downsideDeviation();}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisPercentile(QlHistoricalIndexAnalysis *o, double y, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->percentile(y);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisGaussianPercentile(QlHistoricalIndexAnalysis *o, double y, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->gaussianPercentile(y);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisValueAtRisk(QlHistoricalIndexAnalysis *o, double centile, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->valueAtRisk(centile);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisGaussianValueAtRisk(QlHistoricalIndexAnalysis *o, double centile, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->gaussianValueAtRisk(centile);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisExpectedShortfall(QlHistoricalIndexAnalysis *o, double centile, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->expectedShortfall(centile);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisGaussianExpectedShortfall(QlHistoricalIndexAnalysis *o, double centile, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->gaussianExpectedShortfall(centile);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisPotentialUpside(QlHistoricalIndexAnalysis *o, double centile, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->potentialUpside(centile);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisGaussianPotentialUpside(QlHistoricalIndexAnalysis *o, double centile, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->gaussianPotentialUpside(centile);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisRegret(QlHistoricalIndexAnalysis *o, double target, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->regret(target);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisShortfall(QlHistoricalIndexAnalysis *o, double target, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->shortfall(target);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisGaussianShortfall(QlHistoricalIndexAnalysis *o, double target, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->gaussianShortfall(target);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisAverageShortfall(QlHistoricalIndexAnalysis *o, double target, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->averageShortfall(target);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisGaussianAverageShortfall(QlHistoricalIndexAnalysis *o, double target, unsigned *len, double **vs, char **e) {
  try {fillVectorOut([&] {return (*arg(o))->stats()->gaussianAverageShortfall(target);}, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisCovariance(QlHistoricalIndexAnalysis *o, unsigned *rows, unsigned *cols, unsigned *len, double **vs, char **e) {
  try {fillMatrixOut([&] {return (*arg(o))->stats()->covariance();}, rows, cols, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

void qlHistoricalIndexAnalysisCorrelation(QlHistoricalIndexAnalysis *o, unsigned *rows, unsigned *cols, unsigned *len, double **vs, char **e) {
  try {fillMatrixOut([&] {return (*arg(o))->stats()->correlation();}, rows, cols, len, vs);
  } catch (std::exception& er) {handleException<double*>(e, er);}}

Garch11 *qlGarch11(double alpha, double beta, double vl, char **e) {
  try {return alloc(new Garch11(alpha, beta, vl));
  } catch (std::exception& er) {return handleException<Garch11*>(e, er);}}
Garch11 *qlGarch11Calibrated(unsigned datesLen, int *dates, unsigned /*valuesLen*/, double *values, int mode, char **e) {
  try {
    Garch11::time_series ts;
    for (unsigned n = 0; n < datesLen; ++n) ts[Date(dates[n])] = values[n];
    return alloc(new Garch11(ts, (Garch11::Mode)mode));
  } catch (std::exception& er) {return handleException<Garch11*>(e, er);}}
void qlFreeGarch11(Garch11 *o) {del(o);}
double qlGarch11Alpha(Garch11 *o) {return arg(o)->alpha();}
double qlGarch11Beta(Garch11 *o) {return arg(o)->beta();}
double qlGarch11Omega(Garch11 *o) {return arg(o)->omega();}
double qlGarch11LtVol(Garch11 *o) {return arg(o)->ltVol();}
double qlGarch11LogLikelihood(Garch11 *o) {return arg(o)->logLikelihood();}
double qlGarch11Forecast(Garch11 *o, double r, double sigma2) {return arg(o)->forecast(r, sigma2);}
void qlGarch11Calculate(Garch11 *o, unsigned datesLen, int *dates, unsigned /*valuesLen*/, double *values,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  Garch11 *g = arg(o);
  realSeriesCalculate([g](const TimeSeries<Real>& ts){return g->calculate(ts);},
      datesLen, dates, values, outDatesLen, outDates, outValuesLen, outValues, e);
}

void qlGarmanKlassSimpleSigma(double yearFraction,
    unsigned datesLen, int *dates, unsigned /*opensLen*/, double *opens, unsigned /*closesLen*/, double *closes,
    unsigned /*highsLen*/, double *highs, unsigned /*lowsLen*/, double *lows,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  GarmanKlassSimpleSigma est(yearFraction);
  intervalPriceSeriesCalculate([&est](const TimeSeries<IntervalPrice>& ts){return est.calculate(ts);},
      datesLen, dates, opens, closes, highs, lows, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlGarmanKlassSigma1(double yearFraction, double marketOpenFraction,
    unsigned datesLen, int *dates, unsigned /*opensLen*/, double *opens, unsigned /*closesLen*/, double *closes,
    unsigned /*highsLen*/, double *highs, unsigned /*lowsLen*/, double *lows,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  GarmanKlassSigma1 est(yearFraction, marketOpenFraction);
  intervalPriceSeriesCalculate([&est](const TimeSeries<IntervalPrice>& ts){return est.calculate(ts);},
      datesLen, dates, opens, closes, highs, lows, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlParkinsonSigma(double yearFraction,
    unsigned datesLen, int *dates, unsigned /*opensLen*/, double *opens, unsigned /*closesLen*/, double *closes,
    unsigned /*highsLen*/, double *highs, unsigned /*lowsLen*/, double *lows,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  ParkinsonSigma est(yearFraction);
  intervalPriceSeriesCalculate([&est](const TimeSeries<IntervalPrice>& ts){return est.calculate(ts);},
      datesLen, dates, opens, closes, highs, lows, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlGarmanKlassSigma3(double yearFraction, double marketOpenFraction,
    unsigned datesLen, int *dates, unsigned /*opensLen*/, double *opens, unsigned /*closesLen*/, double *closes,
    unsigned /*highsLen*/, double *highs, unsigned /*lowsLen*/, double *lows,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  GarmanKlassSigma3 est(yearFraction, marketOpenFraction);
  intervalPriceSeriesCalculate([&est](const TimeSeries<IntervalPrice>& ts){return est.calculate(ts);},
      datesLen, dates, opens, closes, highs, lows, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlGarmanKlassSigma4(double yearFraction,
    unsigned datesLen, int *dates, unsigned /*opensLen*/, double *opens, unsigned /*closesLen*/, double *closes,
    unsigned /*highsLen*/, double *highs, unsigned /*lowsLen*/, double *lows,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  GarmanKlassSigma4 est(yearFraction);
  intervalPriceSeriesCalculate([&est](const TimeSeries<IntervalPrice>& ts){return est.calculate(ts);},
      datesLen, dates, opens, closes, highs, lows, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlGarmanKlassSigma5(double yearFraction,
    unsigned datesLen, int *dates, unsigned /*opensLen*/, double *opens, unsigned /*closesLen*/, double *closes,
    unsigned /*highsLen*/, double *highs, unsigned /*lowsLen*/, double *lows,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  GarmanKlassSigma5 est(yearFraction);
  intervalPriceSeriesCalculate([&est](const TimeSeries<IntervalPrice>& ts){return est.calculate(ts);},
      datesLen, dates, opens, closes, highs, lows, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlGarmanKlassSigma6(double yearFraction, double marketOpenFraction,
    unsigned datesLen, int *dates, unsigned /*opensLen*/, double *opens, unsigned /*closesLen*/, double *closes,
    unsigned /*highsLen*/, double *highs, unsigned /*lowsLen*/, double *lows,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  GarmanKlassSigma6 est(yearFraction, marketOpenFraction);
  intervalPriceSeriesCalculate([&est](const TimeSeries<IntervalPrice>& ts){return est.calculate(ts);},
      datesLen, dates, opens, closes, highs, lows, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlConstantVolatilityEstimator(unsigned windowSize,
    unsigned datesLen, int *dates, unsigned /*valuesLen*/, double *values,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  ConstantEstimator est(windowSize);
  realSeriesCalculate([&est](const TimeSeries<Real>& ts){return est.calculate(ts);},
      datesLen, dates, values, outDatesLen, outDates, outValuesLen, outValues, e);
}
void qlSimpleLocalVolatilityEstimator(double yearFraction,
    unsigned datesLen, int *dates, unsigned /*valuesLen*/, double *values,
    unsigned *outDatesLen, int **outDates, unsigned *outValuesLen, double **outValues, char **e) {
  SimpleLocalEstimator est(yearFraction);
  realSeriesCalculate([&est](const TimeSeries<Real>& ts){return est.calculate(ts);},
      datesLen, dates, values, outDatesLen, outDates, outValuesLen, outValues, e);
}
}
/* vim: set ft=cpp ff=unix ts=8 sts=2 sw=2 et: */