inline void Observable::notifyObservers() { bool successful = true; std::string errMsg; for (iterator i=observers_.begin(); i!=observers_.end(); ++i) { try { (*i)->update(); } catch (std::exception& e) { // quite a dilemma. If we don't catch the exception, // other observers will not receive the notification // and might be left in an incorrect state. If we do // catch it and continue the loop (as we do here) we // lose the exception. The least evil might be to try // and notify all observers, while raising an // exception if something bad happened. successful = false; errMsg = e.what(); } catch (...) { successful = false; } } QL_ENSURE(successful, "could not notify one or more observers: " << errMsg); }
AmortizingFixedRateBond::AmortizingFixedRateBond( Natural settlementDays, const std::vector<Real>& notionals, const Schedule& schedule, const std::vector<Rate>& coupons, const DayCounter& accrualDayCounter, BusinessDayConvention paymentConvention, const Date& issueDate) : Bond(settlementDays, schedule.calendar(), issueDate), frequency_(schedule.tenor().frequency()), dayCounter_(accrualDayCounter) { maturityDate_ = schedule.endDate(); cashflows_ = FixedRateLeg(schedule) .withNotionals(notionals) .withCouponRates(coupons, accrualDayCounter) .withPaymentAdjustment(paymentConvention); addRedemptionsToCashflows(); QL_ENSURE(!cashflows().empty(), "bond with no cashflows!"); }
/* Fonction de calcul de l'accrued des instruments */ DLLEXPORT xloper * xlSwapDV01 (const char * instrumentId_, const char * curveId_, const char * conventionId_, xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlSwapDV01")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; // trigger pour provoquer le recalcul ObjectHandler::validateRange(trigger_, "trigger") ; QuantLib::Real returnValue ; // on récupère la courbe OH_GET_OBJECT(curvePtr, curveId_, ObjectHandler::Object) // on récupère la convention de taux OH_GET_OBJECT(conventionPtr, conventionId_, QuantLibAddin::interestRateConventionObject) QuantLib::Handle<QuantLib::YieldTermStructure> curveLibPtr = QuantLibAddin::CoerceHandle<QuantLibAddin::YieldTermStructure, QuantLib::YieldTermStructure>()(curvePtr) ; QuantLib::Handle<QuantLib::Quote> mySpread( new QuantLib::SimpleQuote(1.0 / 100)) ; // 1 bp QuantLib::Handle<QuantLib::YieldTermStructure> myShiftedCurve( new QuantLib::ZeroSpreadedTermStructure(curveLibPtr, mySpread, conventionPtr->compounding(), conventionPtr->frequency(), conventionPtr->daycounter())) ; // on récupère l'instrument OH_GET_OBJECT(instrumentPtr, instrumentId_, ObjectHandler::Object) /* IRS */ if (instrumentPtr->properties()->className() == "interestRateSwapValueObject") { QuantLib::Handle<QuantLib::vanillaSwap2> swapPtr = QuantLibAddin::CoerceHandle<QuantLibAddin::interestRateSwapObject, QuantLib::vanillaSwap2>()(instrumentPtr) ; returnValue = QuantLib::CashFlows::npv(swapPtr->leg(0), ** curveLibPtr, QuantLib::Unadjusted, QuantLib::Calendar(), false) * swapPtr->receivingLeg(0) ; returnValue += QuantLib::CashFlows::npv(swapPtr->leg(1), ** curveLibPtr, QuantLib::Unadjusted, QuantLib::Calendar(), false) * swapPtr->receivingLeg(1) ; returnValue -= QuantLib::CashFlows::npv(swapPtr->leg(0), ** myShiftedCurve, QuantLib::Unadjusted, QuantLib::Calendar(), false) * swapPtr->receivingLeg(0) ; returnValue -= QuantLib::CashFlows::npv(swapPtr->leg(1), ** myShiftedCurve, QuantLib::Unadjusted, QuantLib::Calendar(), false) * swapPtr->receivingLeg(1) ; } /* jambe fixe */ else if (instrumentPtr->properties()->className() == "fixedLegAustraliaValueObject" || instrumentPtr->properties()->className() == "fixedLegUnitedStatesValueObject"|| instrumentPtr->properties()->className() == "floatLegAustraliaValueObject" || instrumentPtr->properties()->className() == "floatLegUnitedStatesValueObject") { OH_GET_REFERENCE(instrumentLibObj, instrumentId_, QuantLibAddin::Leg, QuantLib::Leg) returnValue = QuantLib::CashFlows::npv(* instrumentLibObj, ** curveLibPtr, QuantLib::Unadjusted, QuantLib::Calendar(), false) ; returnValue -= QuantLib::CashFlows::npv(* instrumentLibObj, ** myShiftedCurve, QuantLib::Unadjusted, QuantLib::Calendar(), false) ; } else { // ici pour les autres instruments QL_FAIL("unknown instrument type") ; } static XLOPER returnOper ; ObjectHandler::scalarToOper(returnValue, returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; static XLOPER returnOper ; returnOper.xltype = xltypeErr ; returnOper.val.err = xlerrValue ; return & returnOper ; } } ;
void BinomialVanillaEngine<T>::calculate() const { DayCounter rfdc = process_->riskFreeRate()->dayCounter(); DayCounter divdc = process_->dividendYield()->dayCounter(); DayCounter voldc = process_->blackVolatility()->dayCounter(); Calendar volcal = process_->blackVolatility()->calendar(); Real s0 = process_->stateVariable()->value(); QL_REQUIRE(s0 > 0.0, "negative or null underlying given"); Volatility v = process_->blackVolatility()->blackVol( arguments_.exercise->lastDate(), s0); Date maturityDate = arguments_.exercise->lastDate(); Rate r = process_->riskFreeRate()->zeroRate(maturityDate, rfdc, Continuous, NoFrequency); Rate q = process_->dividendYield()->zeroRate(maturityDate, divdc, Continuous, NoFrequency); Date referenceDate = process_->riskFreeRate()->referenceDate(); // binomial trees with constant coefficient Handle<YieldTermStructure> flatRiskFree( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, r, rfdc))); Handle<YieldTermStructure> flatDividends( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, q, divdc))); Handle<BlackVolTermStructure> flatVol( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(referenceDate, volcal, v, voldc))); boost::shared_ptr<PlainVanillaPayoff> payoff = boost::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-plain payoff given"); Time maturity = rfdc.yearFraction(referenceDate, maturityDate); boost::shared_ptr<StochasticProcess1D> bs( new GeneralizedBlackScholesProcess( process_->stateVariable(), flatDividends, flatRiskFree, flatVol)); TimeGrid grid(maturity, timeSteps_); boost::shared_ptr<T> tree(new T(bs, maturity, timeSteps_, payoff->strike())); boost::shared_ptr<BlackScholesLattice<T> > lattice( new BlackScholesLattice<T>(tree, r, maturity, timeSteps_)); DiscretizedVanillaOption option(arguments_, *process_, grid); option.initialize(lattice, maturity); // Partial derivatives calculated from various points in the // binomial tree (Odegaard) // Rollback to third-last step, and get underlying price (s2) & // option values (p2) at this point option.rollback(grid[2]); Array va2(option.values()); QL_ENSURE(va2.size() == 3, "Expect 3 nodes in grid at second step"); Real p2h = va2[2]; // high-price Real s2 = lattice->underlying(2, 2); // high price // Rollback to second-last step, and get option value (p1) at // this point option.rollback(grid[1]); Array va(option.values()); QL_ENSURE(va.size() == 2, "Expect 2 nodes in grid at first step"); Real p1 = va[1]; // Finally, rollback to t=0 option.rollback(0.0); Real p0 = option.presentValue(); Real s1 = lattice->underlying(1, 1); // Calculate partial derivatives Real delta0 = (p1-p0)/(s1-s0); // dp/ds Real delta1 = (p2h-p1)/(s2-s1); // dp/ds // Store results results_.value = p0; results_.delta = delta0; results_.gamma = 2.0*(delta1-delta0)/(s2-s0); //d(delta)/ds results_.theta = blackScholesTheta(process_, results_.value, results_.delta, results_.gamma); }
void IterativeBootstrap<Curve>::calculate() const { Size n = ts_->instruments_.size(); // ensure rate helpers are sorted std::sort(ts_->instruments_.begin(), ts_->instruments_.end(), detail::BootstrapHelperSorter()); // check that there is no instruments with the same maturity for (Size i=1; i<n; ++i) { Date m1 = ts_->instruments_[i-1]->latestDate(), m2 = ts_->instruments_[i]->latestDate(); QL_REQUIRE(m1 != m2, "two instruments have the same maturity ("<< m1 <<")"); } // check that there is no instruments with invalid quote for (Size i=0; i<n; ++i) QL_REQUIRE(ts_->instruments_[i]->quote()->isValid(), io::ordinal(i+1) << " instrument (maturity: " << ts_->instruments_[i]->latestDate() << ") has an invalid quote"); // setup instruments for (Size i=0; i<n; ++i) { // don't try this at home! // This call creates instruments, and removes "const". // There is a significant interaction with observability. ts_->instruments_[i]->setTermStructure(const_cast<Curve*>(ts_)); } // calculate dates and times ts_->dates_ = std::vector<Date>(n+1); ts_->times_ = std::vector<Time>(n+1); ts_->dates_[0] = Traits::initialDate(ts_); ts_->times_[0] = ts_->timeFromReference(ts_->dates_[0]); for (Size i=0; i<n; ++i) { ts_->dates_[i+1] = ts_->instruments_[i]->latestDate(); ts_->times_[i+1] = ts_->timeFromReference(ts_->dates_[i+1]); } // set initial guess only if the current curve cannot be used as guess if (validCurve_) { QL_ENSURE(ts_->data_.size() == n+1, "dimension mismatch: expected " << n+1 << ", actual " << ts_->data_.size()); } else { ts_->data_ = std::vector<Rate>(n+1); ts_->data_[0] = Traits::initialValue(ts_); for (Size i=0; i<n; ++i) ts_->data_[i+1] = Traits::initialGuess(); } Brent solver; Size maxIterations = Traits::maxIterations(); for (Size iteration=0; ; ++iteration) { std::vector<Rate> previousData = ts_->data_; // restart from the previous interpolation if (validCurve_) { ts_->interpolation_ = ts_->interpolator_.interpolate( ts_->times_.begin(), ts_->times_.end(), ts_->data_.begin()); } for (Size i=1; i<n+1; ++i) { // calculate guess before extending interpolation // to ensure that any extrapolation is performed // using the curve bootstrapped so far and no more boost::shared_ptr<typename Traits::helper> instrument = ts_->instruments_[i-1]; Rate guess = 0.0; if (validCurve_ || iteration>0) { guess = ts_->data_[i]; } else if (i==1) { guess = Traits::initialGuess(); } else { // most traits extrapolate guess = Traits::guess(ts_, ts_->dates_[i]); } // bracket Real min = Traits::minValueAfter(i, ts_->data_); Real max = Traits::maxValueAfter(i, ts_->data_); if (guess<=min || guess>=max) guess = (min+max)/2.0; if (!validCurve_ && iteration == 0) { // extend interpolation a point at a time try { ts_->interpolation_ = ts_->interpolator_.interpolate( ts_->times_.begin(), ts_->times_.begin()+i+1, ts_->data_.begin()); } catch(...) { if (!Interpolator::global) throw; // no chance to fix it in a later iteration // otherwise, if the target interpolation is // not usable yet ts_->interpolation_ = Linear().interpolate( ts_->times_.begin(), ts_->times_.begin()+i+1, ts_->data_.begin()); } } // required because we just changed the data // is it really required? ts_->interpolation_.update(); try { BootstrapError<Curve> error(ts_, instrument, i); Real r = solver.solve(error,ts_->accuracy_,guess,min,max); // redundant assignment (as it has been already performed // by BootstrapError in solve procedure), but safe ts_->data_[i] = r; } catch (std::exception &e) { validCurve_ = false; QL_FAIL(io::ordinal(iteration+1) << " iteration: " "failed at " << io::ordinal(i) << " instrument" ", maturity " << ts_->dates_[i] << ", reference date " << ts_->dates_[0] << ": " << e.what()); } } if (!Interpolator::global) break; // no need for convergence loop else if (!validCurve_ && iteration == 0) { // ensure the target interpolation is used ts_->interpolation_ = ts_->interpolator_.interpolate(ts_->times_.begin(), ts_->times_.end(), ts_->data_.begin()); // at least one more iteration is needed to check convergence continue; } // exit conditions Real improvement = 0.0; for (Size i=1; i<n+1; ++i) improvement=std::max(improvement, std::fabs(ts_->data_[i]-previousData[i])); if (improvement<=ts_->accuracy_) // convergence reached break; QL_REQUIRE(iteration+1 < maxIterations, "convergence not reached after " << iteration+1 << " iterations; last improvement " << improvement << ", required accuracy " << ts_->accuracy_); } validCurve_ = true; }
void LocalBootstrap<Curve>::calculate() const { validCurve_ = false; Size nInsts = ts_->instruments_.size(); // ensure rate helpers are sorted std::sort(ts_->instruments_.begin(), ts_->instruments_.end(), detail::BootstrapHelperSorter()); // check that there is no instruments with the same maturity for (Size i=1; i<nInsts; ++i) { Date m1 = ts_->instruments_[i-1]->latestDate(), m2 = ts_->instruments_[i]->latestDate(); QL_REQUIRE(m1 != m2, "two instruments have the same maturity ("<< m1 <<")"); } // check that there is no instruments with invalid quote for (Size i=0; i<nInsts; ++i) QL_REQUIRE(ts_->instruments_[i]->quote()->isValid(), io::ordinal(i+1) << " instrument (maturity: " << ts_->instruments_[i]->latestDate() << ") has an invalid quote"); // setup instruments for (Size i=0; i<nInsts; ++i) { // don't try this at home! // This call creates instruments, and removes "const". // There is a significant interaction with observability. ts_->instruments_[i]->setTermStructure(const_cast<Curve*>(ts_)); } // set initial guess only if the current curve cannot be used as guess if (validCurve_) QL_ENSURE(ts_->data_.size() == nInsts+1, "dimension mismatch: expected " << nInsts+1 << ", actual " << ts_->data_.size()); else { ts_->data_ = std::vector<Rate>(nInsts+1); ts_->data_[0] = Traits::initialValue(ts_); } // calculate dates and times ts_->dates_ = std::vector<Date>(nInsts+1); ts_->times_ = std::vector<Time>(nInsts+1); ts_->dates_[0] = Traits::initialDate(ts_); ts_->times_[0] = ts_->timeFromReference(ts_->dates_[0]); for (Size i=0; i<nInsts; ++i) { ts_->dates_[i+1] = ts_->instruments_[i]->latestDate(); ts_->times_[i+1] = ts_->timeFromReference(ts_->dates_[i+1]); if (!validCurve_) ts_->data_[i+1] = ts_->data_[i]; } LevenbergMarquardt solver(ts_->accuracy_, ts_->accuracy_, ts_->accuracy_); EndCriteria endCriteria(100, 10, 0.00, ts_->accuracy_, 0.00); PositiveConstraint posConstraint; NoConstraint noConstraint; Constraint& solverConstraint = forcePositive_ ? static_cast<Constraint&>(posConstraint) : static_cast<Constraint&>(noConstraint); // now start the bootstrapping. Size iInst = localisation_-1; Size dataAdjust = Curve::interpolator_type::dataSizeAdjustment; do { Size initialDataPt = iInst+1-localisation_+dataAdjust; Array startArray(localisation_+1-dataAdjust); for (Size j = 0; j < startArray.size()-1; ++j) startArray[j] = ts_->data_[initialDataPt+j]; // here we are extending the interpolation a point at a // time... but the local interpolator can make an // approximation for the final localisation period. // e.g. if the localisation is 2, then the first section // of the curve will be solved using the first 2 // instruments... with the local interpolator making // suitable boundary conditions. ts_->interpolation_ = ts_->interpolator_.localInterpolate( ts_->times_.begin(), ts_->times_.begin()+(iInst + 2), ts_->data_.begin(), localisation_, ts_->interpolation_, nInsts+1); if (iInst >= localisation_) { startArray[localisation_-dataAdjust] = Traits::guess(iInst, ts_, false, 0); // ? } else { startArray[localisation_-dataAdjust] = ts_->data_[0]; } PenaltyFunction<Curve> currentCost( ts_, initialDataPt, ts_->instruments_.begin() + (iInst - localisation_+1), ts_->instruments_.begin() + (iInst+1)); Problem toSolve(currentCost, solverConstraint, startArray); EndCriteria::Type endType = solver.minimize(toSolve, endCriteria); // check the end criteria QL_REQUIRE(endType == EndCriteria::StationaryFunctionAccuracy || endType == EndCriteria::StationaryFunctionValue, "Unable to strip yieldcurve to required accuracy " ); ++iInst; } while ( iInst < nInsts ); validCurve_ = true; }
Schedule::Schedule(Date effectiveDate, const Date& terminationDate, const Period& tenor, const Calendar& cal, BusinessDayConvention convention, BusinessDayConvention terminationDateConvention, DateGeneration::Rule rule, bool endOfMonth, const Date& first, const Date& nextToLast) : tenor_(tenor), calendar_(cal), convention_(convention), terminationDateConvention_(terminationDateConvention), rule_(rule), endOfMonth_(allowsEndOfMonth(tenor) ? endOfMonth : false), firstDate_(first==effectiveDate ? Date() : first), nextToLastDate_(nextToLast==terminationDate ? Date() : nextToLast) { // sanity checks QL_REQUIRE(terminationDate != Date(), "null termination date"); // in many cases (e.g. non-expired bonds) the effective date is not // really necessary. In these cases a decent placeholder is enough if (effectiveDate==Date() && first==Date() && rule==DateGeneration::Backward) { Date evalDate = Settings::instance().evaluationDate(); QL_REQUIRE(evalDate < terminationDate, "null effective date"); Natural y; if (nextToLast != Date()) { y = (nextToLast - evalDate)/366 + 1; effectiveDate = nextToLast - y*Years; } else { y = (terminationDate - evalDate)/366 + 1; effectiveDate = terminationDate - y*Years; } } else QL_REQUIRE(effectiveDate != Date(), "null effective date"); QL_REQUIRE(effectiveDate < terminationDate, "effective date (" << effectiveDate << ") later than or equal to termination date (" << terminationDate << ")"); if (tenor.length()==0) rule_ = DateGeneration::Zero; else QL_REQUIRE(tenor.length()>0, "non positive tenor (" << tenor << ") not allowed"); if (firstDate_ != Date()) { switch (*rule_) { case DateGeneration::Backward: case DateGeneration::Forward: QL_REQUIRE(firstDate_ > effectiveDate && firstDate_ < terminationDate, "first date (" << firstDate_ << ") out of effective-termination date range [" << effectiveDate << ", " << terminationDate << ")"); // we should ensure that the above condition is still // verified after adjustment break; case DateGeneration::ThirdWednesday: QL_REQUIRE(IMM::isIMMdate(firstDate_, false), "first date (" << firstDate_ << ") is not an IMM date"); break; case DateGeneration::Zero: case DateGeneration::Twentieth: case DateGeneration::TwentiethIMM: case DateGeneration::OldCDS: case DateGeneration::CDS: QL_FAIL("first date incompatible with " << *rule_ << " date generation rule"); default: QL_FAIL("unknown rule (" << Integer(*rule_) << ")"); } } if (nextToLastDate_ != Date()) { switch (*rule_) { case DateGeneration::Backward: case DateGeneration::Forward: QL_REQUIRE(nextToLastDate_ > effectiveDate && nextToLastDate_ < terminationDate, "next to last date (" << nextToLastDate_ << ") out of effective-termination date range (" << effectiveDate << ", " << terminationDate << "]"); // we should ensure that the above condition is still // verified after adjustment break; case DateGeneration::ThirdWednesday: QL_REQUIRE(IMM::isIMMdate(nextToLastDate_, false), "next-to-last date (" << nextToLastDate_ << ") is not an IMM date"); break; case DateGeneration::Zero: case DateGeneration::Twentieth: case DateGeneration::TwentiethIMM: case DateGeneration::OldCDS: case DateGeneration::CDS: QL_FAIL("next to last date incompatible with " << *rule_ << " date generation rule"); default: QL_FAIL("unknown rule (" << Integer(*rule_) << ")"); } } // calendar needed for endOfMonth adjustment Calendar nullCalendar = NullCalendar(); Integer periods = 1; Date seed, exitDate; switch (*rule_) { case DateGeneration::Zero: tenor_ = 0*Years; dates_.push_back(effectiveDate); dates_.push_back(terminationDate); isRegular_.push_back(true); break; case DateGeneration::Backward: dates_.push_back(terminationDate); seed = terminationDate; if (nextToLastDate_ != Date()) { dates_.insert(dates_.begin(), nextToLastDate_); Date temp = nullCalendar.advance(seed, -periods*(*tenor_), convention, *endOfMonth_); if (temp!=nextToLastDate_) isRegular_.insert(isRegular_.begin(), false); else isRegular_.insert(isRegular_.begin(), true); seed = nextToLastDate_; } exitDate = effectiveDate; if (firstDate_ != Date()) exitDate = firstDate_; for (;;) { Date temp = nullCalendar.advance(seed, -periods*(*tenor_), convention, *endOfMonth_); if (temp < exitDate) { if (firstDate_ != Date() && (calendar_.adjust(dates_.front(),convention)!= calendar_.adjust(firstDate_,convention))) { dates_.insert(dates_.begin(), firstDate_); isRegular_.insert(isRegular_.begin(), false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.front(),convention)!= calendar_.adjust(temp,convention)) { dates_.insert(dates_.begin(), temp); isRegular_.insert(isRegular_.begin(), true); } ++periods; } } if (calendar_.adjust(dates_.front(),convention)!= calendar_.adjust(effectiveDate,convention)) { dates_.insert(dates_.begin(), effectiveDate); isRegular_.insert(isRegular_.begin(), false); } break; case DateGeneration::Twentieth: case DateGeneration::TwentiethIMM: case DateGeneration::ThirdWednesday: case DateGeneration::OldCDS: case DateGeneration::CDS: QL_REQUIRE(!*endOfMonth_, "endOfMonth convention incompatible with " << *rule_ << " date generation rule"); // fall through case DateGeneration::Forward: if (*rule_ == DateGeneration::CDS) { dates_.push_back(previousTwentieth(effectiveDate, DateGeneration::CDS)); } else { dates_.push_back(effectiveDate); } seed = dates_.back(); if (firstDate_!=Date()) { dates_.push_back(firstDate_); Date temp = nullCalendar.advance(seed, periods*(*tenor_), convention, *endOfMonth_); if (temp!=firstDate_) isRegular_.push_back(false); else isRegular_.push_back(true); seed = firstDate_; } else if (*rule_ == DateGeneration::Twentieth || *rule_ == DateGeneration::TwentiethIMM || *rule_ == DateGeneration::OldCDS || *rule_ == DateGeneration::CDS) { Date next20th = nextTwentieth(effectiveDate, *rule_); if (*rule_ == DateGeneration::OldCDS) { // distance rule inforced in natural days static const BigInteger stubDays = 30; if (next20th - effectiveDate < stubDays) { // +1 will skip this one and get the next next20th = nextTwentieth(next20th + 1, *rule_); } } if (next20th != effectiveDate) { dates_.push_back(next20th); isRegular_.push_back(false); seed = next20th; } } exitDate = terminationDate; if (nextToLastDate_ != Date()) exitDate = nextToLastDate_; for (;;) { Date temp = nullCalendar.advance(seed, periods*(*tenor_), convention, *endOfMonth_); if (temp > exitDate) { if (nextToLastDate_ != Date() && (calendar_.adjust(dates_.back(),convention)!= calendar_.adjust(nextToLastDate_,convention))) { dates_.push_back(nextToLastDate_); isRegular_.push_back(false); } break; } else { // skip dates that would result in duplicates // after adjustment if (calendar_.adjust(dates_.back(),convention)!= calendar_.adjust(temp,convention)) { dates_.push_back(temp); isRegular_.push_back(true); } ++periods; } } if (calendar_.adjust(dates_.back(),terminationDateConvention)!= calendar_.adjust(terminationDate,terminationDateConvention)) { if (*rule_ == DateGeneration::Twentieth || *rule_ == DateGeneration::TwentiethIMM || *rule_ == DateGeneration::OldCDS || *rule_ == DateGeneration::CDS) { dates_.push_back(nextTwentieth(terminationDate, *rule_)); isRegular_.push_back(true); } else { dates_.push_back(terminationDate); isRegular_.push_back(false); } } break; default: QL_FAIL("unknown rule (" << Integer(*rule_) << ")"); } // adjustments if (*rule_==DateGeneration::ThirdWednesday) for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = Date::nthWeekday(3, Wednesday, dates_[i].month(), dates_[i].year()); if (*endOfMonth_ && calendar_.isEndOfMonth(seed)) { // adjust to end of month if (convention == Unadjusted) { for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = Date::endOfMonth(dates_[i]); } else { for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = calendar_.endOfMonth(dates_[i]); } if (terminationDateConvention != Unadjusted) { dates_.front() = calendar_.endOfMonth(dates_.front()); dates_.back() = calendar_.endOfMonth(dates_.back()); } else { // the termination date is the first if going backwards, // the last otherwise. if (*rule_ == DateGeneration::Backward) dates_.back() = Date::endOfMonth(dates_.back()); else dates_.front() = Date::endOfMonth(dates_.front()); } } else { // first date not adjusted for CDS schedules if (*rule_ != DateGeneration::OldCDS) dates_[0] = calendar_.adjust(dates_[0], convention); for (Size i=1; i<dates_.size()-1; ++i) dates_[i] = calendar_.adjust(dates_[i], convention); // termination date is NOT adjusted as per ISDA // specifications, unless otherwise specified in the // confirmation of the deal or unless we're creating a CDS // schedule if (terminationDateConvention != Unadjusted || *rule_ == DateGeneration::Twentieth || *rule_ == DateGeneration::TwentiethIMM || *rule_ == DateGeneration::OldCDS || *rule_ == DateGeneration::CDS) { dates_.back() = calendar_.adjust(dates_.back(), terminationDateConvention); } } // Final safety checks to remove extra next-to-last date, if // necessary. It can happen to be equal or later than the end // date due to EOM adjustments (see the Schedule test suite // for an example). if (dates_.size() >= 2 && dates_[dates_.size()-2] >= dates_.back()) { isRegular_[dates_.size()-2] = (dates_[dates_.size()-2] == dates_.back()); dates_[dates_.size()-2] = dates_.back(); dates_.pop_back(); isRegular_.pop_back(); } if (dates_.size() >= 2 && dates_[1] <= dates_.front()) { isRegular_[1] = (dates_[1] == dates_.front()); dates_[1] = dates_.front(); dates_.erase(dates_.begin()); isRegular_.erase(isRegular_.begin()); } QL_ENSURE(dates_.size()>1, "degenerate single date (" << dates_[0] << ") schedule" << "\n seed date: " << seed << "\n exit date: " << exitDate << "\n effective date: " << effectiveDate << "\n first date: " << first << "\n next to last date: " << nextToLast << "\n termination date: " << terminationDate << "\n generation rule: " << *rule_ << "\n end of month: " << *endOfMonth_); }
void SwaptionVolCube1::sabrCalibrationSection( const Cube& marketVolCube, Cube& parametersCube, const Period& swapTenor) const { const std::vector<Time>& optionTimes = marketVolCube.optionTimes(); const std::vector<Time>& swapLengths = marketVolCube.swapLengths(); const std::vector<Date>& optionDates = marketVolCube.optionDates(); const std::vector<Period>& swapTenors = marketVolCube.swapTenors(); Size k = std::find(swapTenors.begin(), swapTenors.end(), swapTenor) - swapTenors.begin(); QL_REQUIRE(k != swapTenors.size(), "swap tenor not found"); std::vector<Real> calibrationResult(8,0.); const std::vector<Matrix>& tmpMarketVolCube = marketVolCube.points(); std::vector<Real> strikes(strikeSpreads_.size()); std::vector<Real> volatilities(strikeSpreads_.size()); for (Size j=0; j<optionTimes.size(); j++) { Rate atmForward = atmStrike(optionDates[j], swapTenors[k]); strikes.clear(); volatilities.clear(); for (Size i=0; i<nStrikes_; i++){ Real strike = atmForward+strikeSpreads_[i]; if(strike>=MINSTRIKE) { strikes.push_back(strike); volatilities.push_back(tmpMarketVolCube[i][j][k]); } } const std::vector<Real>& guess = parametersGuess_.operator()( optionTimes[j], swapLengths[k]); const boost::shared_ptr<SABRInterpolation> sabrInterpolation = boost::shared_ptr<SABRInterpolation>(new SABRInterpolation(strikes.begin(), strikes.end(), volatilities.begin(), optionTimes[j], atmForward, guess[0], guess[1], guess[2], guess[3], isParameterFixed_[0], isParameterFixed_[1], isParameterFixed_[2], isParameterFixed_[3], vegaWeightedSmileFit_, endCriteria_, optMethod_, errorAccept_, useMaxError_, maxGuesses_)); sabrInterpolation->update(); Real interpolationError = sabrInterpolation->rmsError(); calibrationResult[0]=sabrInterpolation->alpha(); calibrationResult[1]=sabrInterpolation->beta(); calibrationResult[2]=sabrInterpolation->nu(); calibrationResult[3]=sabrInterpolation->rho(); calibrationResult[4]=atmForward; calibrationResult[5]=interpolationError; calibrationResult[6]=sabrInterpolation->maxError(); calibrationResult[7]=sabrInterpolation->endCriteria(); QL_ENSURE(calibrationResult[7]!=EndCriteria::MaxIterations, "section calibration failed: " "option tenor " << optionDates[j] << ", swap tenor " << swapTenors[k] << ": max iteration (" << endCriteria_->maxIterations() << ")" << ", alpha " << calibrationResult[0]<< ", beta " << calibrationResult[1] << ", nu " << calibrationResult[2] << ", rho " << calibrationResult[3] << ", max error " << calibrationResult[6] << ", error " << calibrationResult[5] ); QL_ENSURE(useMaxError_ ? calibrationResult[6] : calibrationResult[5] < maxErrorTolerance_, "section calibration failed: " "option tenor " << optionDates[j] << ", swap tenor " << swapTenors[k] << (useMaxError_ ? ": max error " : ": error ") << (useMaxError_ ? calibrationResult[6] : calibrationResult[5]) << ", alpha " << calibrationResult[0] << ", beta " << calibrationResult[1] << ", nu " << calibrationResult[2] << ", rho " << calibrationResult[3] << (useMaxError_ ? ": error" : ": max error ") << (useMaxError_ ? calibrationResult[5] : calibrationResult[6]) ); parametersCube.setPoint(optionDates[j], swapTenors[k], optionTimes[j], swapLengths[k], calibrationResult); parametersCube.updateInterpolators(); } }
/* enregistre un TIPS */ DLLEXPORT xloper * xlInitiateAussieNote (const char * objectID_, const double * issueDate_, xloper * effectiveDate_, xloper * firstCouponDate_, xloper * lastCouponDate_, const double * maturityDate_, const double * couponRate_, xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInitiateAussieNote")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; // trigger pour provoquer le recalcul ObjectHandler::validateRange(trigger_, "trigger") ; ObjectHandler::validateRange(effectiveDate_, "effective Date") ; ObjectHandler::validateRange(firstCouponDate_, "first Coupon Date") ; ObjectHandler::validateRange(lastCouponDate_, "last Coupon Date") ; ObjectHandler::ConvertOper myOper1(* effectiveDate_) ; ObjectHandler::ConvertOper myOper2(* firstCouponDate_) ; ObjectHandler::ConvertOper myOper3(* lastCouponDate_) ; QuantLib::Date issueDate(static_cast<QuantLib::BigInteger>(* issueDate_)) ; QuantLib::Date effectiveDate(myOper1.missing() ? issueDate : static_cast<QuantLib::Date>(myOper1)) ; QuantLib::Date firstCouponDate(myOper2.missing() ? QuantLib::Date() : static_cast<QuantLib::Date>(myOper2)) ; QuantLib::Date lastCouponDate(myOper3.missing() ? QuantLib::Date() : static_cast<QuantLib::Date>(myOper3)) ; QuantLib::Date maturityDate(static_cast<QuantLib::BigInteger>(* maturityDate_)) ; // Construction du value object boost::shared_ptr<QuantLibAddin::ValueObjects::australianTreasuryNoteValueObject> myBondValueObject( new QuantLibAddin::ValueObjects::australianTreasuryNoteValueObject(objectID_, true)) ; // instanciation de l'instrument boost::shared_ptr<QuantLibAddin::australianTreasuryNoteObject> myBondObject( new QuantLibAddin::australianTreasuryNoteObject(myBondValueObject, issueDate, effectiveDate, firstCouponDate, lastCouponDate, maturityDate, QuantLib::Rate(* couponRate_), true)) ; // stockage de l'objet std::string returnValue = ObjectHandler::RepositoryXL::instance().storeObject(objectID_, myBondObject, true) ; // on force la réécriture static XLOPER returnOper ; ObjectHandler::scalarToOper(returnValue, returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; static XLOPER returnOper ; ObjectHandler::scalarToOper(e.what(), returnOper) ; return & returnOper ; } } ;
/* enregistre un helper pour un depôt */ DLLEXPORT xloper * xlInitiateDepositBootstrapHelper (const char * objectId_, const char * depositId_, const double * depositPrice_, const xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInitiateDepositBootstrapHelper")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; // trigger pour provoquer le recalcul ObjectHandler::validateRange(trigger_, "trigger") ; OH_GET_REFERENCE(depositPtr, depositId_, QuantLibAddin::depositObject, QuantLib::deposit) // creation de la quote boost::shared_ptr<QuantLib::Quote> myQuote( new QuantLib::SimpleQuote(* depositPrice_)) ; // création du handler QuantLib::Handle<QuantLib::Quote> quoteHandler(myQuote) ; // creation du value object boost::shared_ptr<QuantLibAddin::ValueObjects::depositBootstrapHelperValueObject> depositValueObject( new QuantLibAddin::ValueObjects::depositBootstrapHelperValueObject(objectId_, true)) ; // creation du helper boost::shared_ptr<QuantLibAddin::depositBootstrapHelperObject> depositBootstrapObject( new QuantLibAddin::depositBootstrapHelperObject(depositValueObject, depositPtr, quoteHandler, true)) ; // stockage de l'objet std::string returnValue = ObjectHandler::RepositoryXL::instance().storeObject(objectId_, depositBootstrapObject, true) ; // on force la réécriture static XLOPER returnOper ; ObjectHandler::scalarToOper(returnValue, returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; static XLOPER returnOper ; ObjectHandler::scalarToOper(e.what(), returnOper) ; return & returnOper ; } } ;
/* register a deposit for curve fitting */ DLLEXPORT xloper * xlInitiateDepositBootstrapHelper2 (const char * objectId_, const char * tenor_, const xloper * calendar_, const xloper * settlementDays_, const double * depositYield_, const xloper * annualBasis_, const xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInitiateDepositBootstrapHelper2")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), ""); // range validation ObjectHandler::validateRange(trigger_ , "trigger" ); ObjectHandler::validateRange(calendar_ , "calendar" ); ObjectHandler::validateRange(settlementDays_, "settlement days"); ObjectHandler::validateRange(annualBasis_ , "annual basis" ); // OPER management ObjectHandler::ConvertOper myOper1(* calendar_ ), myOper2(* settlementDays_), myOper3(* annualBasis_ ); // creates a value object boost::shared_ptr<QuantLibAddin::ValueObjects::depositBootstrapHelperValueObject> depositValueObject( new QuantLibAddin::ValueObjects::depositBootstrapHelperValueObject( objectId_, true)) ; // quantlib objects QuantLib::Natural settlementDays( myOper2.missing() ? 2 : static_cast<long>(myOper2)) ; QuantLib::Calendar calendar( myOper1.missing() ? QuantLib::UnitedStates( QuantLib::UnitedStates::Settlement) : ObjectHandler::calendarFactory()( static_cast<std::string>(myOper1))); QuantLib::Date valueDate( calendar.advance( QuantLib::Settings::instance().evaluationDate().value(), settlementDays, QuantLib::Days)) ; QuantLib::DayCounter annualBasis( myOper3.missing() ? QuantLib::Actual360() : ObjectHandler::daycountFactory()( static_cast<std::string>(myOper3))); // creates the deposit boost::shared_ptr<QuantLib::deposit> myDepositPtr ( new QuantLib::deposit( valueDate, calendar.advance(valueDate, ObjectHandler::periodFactory()(tenor_)), calendar, settlementDays, QuantLib::Unadjusted)); // creates the helper boost::shared_ptr<QuantLibAddin::depositBootstrapHelperObject> depositBootstrapObject( new QuantLibAddin::depositBootstrapHelperObject( depositValueObject, myDepositPtr, QuantLib::Handle<QuantLib::Quote>( boost::shared_ptr<QuantLib::Quote>( new QuantLib::SimpleQuote( myDepositPtr->cleanPrice( *depositYield_, annualBasis, QuantLib::Simple, QuantLib::Once, QuantLib::Unadjusted, valueDate)))), true)); // storage of the object std::string returnValue = ObjectHandler::RepositoryXL::instance().storeObject( objectId_, depositBootstrapObject, true); static XLOPER returnOper ; ObjectHandler::scalarToOper(returnValue, returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; static XLOPER returnOper ; ObjectHandler::scalarToOper(e.what(), returnOper) ; return & returnOper ; } };
SymmetricSchurDecomposition::SymmetricSchurDecomposition(const Matrix & s) : diagonal_(s.rows()), eigenVectors_(s.rows(), s.columns(), 0.0) { QL_REQUIRE(s.rows() > 0 && s.columns() > 0, "null matrix given"); QL_REQUIRE(s.rows()==s.columns(), "input matrix must be square"); Size size = s.rows(); for (Size q=0; q<size; q++) { diagonal_[q] = s[q][q]; eigenVectors_[q][q] = 1.0; } Matrix ss = s; std::vector<Real> tmpDiag(diagonal_.begin(), diagonal_.end()); std::vector<Real> tmpAccumulate(size, 0.0); Real threshold, epsPrec = 1e-15; bool keeplooping = true; Size maxIterations = 100, ite = 1; do { //main loop Real sum = 0; for (Size a=0; a<size-1; a++) { for (Size b=a+1; b<size; b++) { sum += std::fabs(ss[a][b]); } } if (sum==0) { keeplooping = false; } else { /* To speed up computation a threshold is introduced to make sure it is worthy to perform the Jacobi rotation */ if (ite<5) threshold = 0.2*sum/(size*size); else threshold = 0.0; Size j, k, l; for (j=0; j<size-1; j++) { for (k=j+1; k<size; k++) { Real sine, rho, cosin, heig, tang, beta; Real smll = std::fabs(ss[j][k]); if(ite> 5 && smll<epsPrec*std::fabs(diagonal_[j]) && smll<epsPrec*std::fabs(diagonal_[k])) { ss[j][k] = 0; } else if (std::fabs(ss[j][k])>threshold) { heig = diagonal_[k]-diagonal_[j]; if (smll<epsPrec*std::fabs(heig)) { tang = ss[j][k]/heig; } else { beta = 0.5*heig/ss[j][k]; tang = 1.0/(std::fabs(beta)+ std::sqrt(1+beta*beta)); if (beta<0) tang = -tang; } cosin = 1/std::sqrt(1+tang*tang); sine = tang*cosin; rho = sine/(1+cosin); heig = tang*ss[j][k]; tmpAccumulate[j] -= heig; tmpAccumulate[k] += heig; diagonal_[j] -= heig; diagonal_[k] += heig; ss[j][k] = 0.0; for (l=0; l+1<=j; l++) jacobiRotate_(ss, rho, sine, l, j, l, k); for (l=j+1; l<=k-1; l++) jacobiRotate_(ss, rho, sine, j, l, l, k); for (l=k+1; l<size; l++) jacobiRotate_(ss, rho, sine, j, l, k, l); for (l=0; l<size; l++) jacobiRotate_(eigenVectors_, rho, sine, l, j, l, k); } } } for (k=0; k<size; k++) { tmpDiag[k] += tmpAccumulate[k]; diagonal_[k] = tmpDiag[k]; tmpAccumulate[k] = 0.0; } } } while (++ite<=maxIterations && keeplooping); QL_ENSURE(ite<=maxIterations, "Too many iterations (" << maxIterations << ") reached"); // sort (eigenvalues, eigenvectors) std::vector<std::pair<Real, std::vector<Real> > > temp(size); std::vector<Real> eigenVector(size); Size row, col; for (col=0; col<size; col++) { std::copy(eigenVectors_.column_begin(col), eigenVectors_.column_end(col), eigenVector.begin()); temp[col] = std::make_pair(diagonal_[col], eigenVector); } std::sort(temp.begin(), temp.end(), std::greater<std::pair<Real, std::vector<Real> > >()); Real maxEv = temp[0].first; for (col=0; col<size; col++) { // check for round-off errors diagonal_[col] = (std::fabs(temp[col].first/maxEv)<1e-16 ? 0.0 : temp[col].first); Real sign = 1.0; if (temp[col].second[0]<0.0) sign = -1.0; for (row=0; row<size; row++) { eigenVectors_[row][col] = sign * temp[col].second[row]; } } }
inline Real CompositeQuote<BinaryFunction>::value() const { QL_ENSURE(isValid(), "invalid CompositeQuote"); return f_(element1_->value(),element2_->value()); }
void ArithmeticAveragedOvernightIndexedCouponPricer::initialize(const FloatingRateCoupon& coupon) { coupon_ = dynamic_cast<const OvernightIndexedCoupon*>(&coupon); QL_ENSURE(coupon_, "wrong coupon type"); }
FloatingRateBond::FloatingRateBond( Natural settlementDays, Real faceAmount, const Date& startDate, const Date& maturityDate, Frequency couponFrequency, const Calendar& calendar, const ext::shared_ptr<IborIndex>& iborIndex, const DayCounter& accrualDayCounter, BusinessDayConvention accrualConvention, BusinessDayConvention paymentConvention, Natural fixingDays, const std::vector<Real>& gearings, const std::vector<Spread>& spreads, const std::vector<Rate>& caps, const std::vector<Rate>& floors, bool inArrears, Real redemption, const Date& issueDate, const Date& stubDate, DateGeneration::Rule rule, bool endOfMonth) : Bond(settlementDays, calendar, issueDate) { maturityDate_ = maturityDate; Date firstDate, nextToLastDate; switch (rule) { case DateGeneration::Backward: firstDate = Date(); nextToLastDate = stubDate; break; case DateGeneration::Forward: firstDate = stubDate; nextToLastDate = Date(); break; case DateGeneration::Zero: case DateGeneration::ThirdWednesday: case DateGeneration::Twentieth: case DateGeneration::TwentiethIMM: QL_FAIL("stub date (" << stubDate << ") not allowed with " << rule << " DateGeneration::Rule"); default: QL_FAIL("unknown DateGeneration::Rule (" << Integer(rule) << ")"); } Schedule schedule(startDate, maturityDate_, Period(couponFrequency), calendar_, accrualConvention, accrualConvention, rule, endOfMonth, firstDate, nextToLastDate); cashflows_ = IborLeg(schedule, iborIndex) .withNotionals(faceAmount) .withPaymentDayCounter(accrualDayCounter) .withPaymentAdjustment(paymentConvention) .withFixingDays(fixingDays) .withGearings(gearings) .withSpreads(spreads) .withCaps(caps) .withFloors(floors) .inArrears(inArrears); addRedemptionsToCashflows(std::vector<Real>(1, redemption)); QL_ENSURE(!cashflows().empty(), "bond with no cashflows!"); QL_ENSURE(redemptions_.size() == 1, "multiple redemptions created"); registerWith(iborIndex); }
/* enregistre une jambe à taux flottant */ DLLEXPORT xloper * xlInitiateFloatLegUnitedStates (const char * objectID_, const double * effectiveDate_, xloper * firstCouponDate_, xloper * lastCouponDate_, const double * maturityDate_, xloper * notional_, const char * indexId_, xloper * frequency_, xloper * daycounter_, xloper * spread_, xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInitiatefloatLegUnitedStates")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; // vérification des codes erreur ObjectHandler::validateRange(trigger_, "trigger") ; ObjectHandler::validateRange(firstCouponDate_, "first Coupon Date") ; ObjectHandler::validateRange(lastCouponDate_, "last Coupon Date") ; ObjectHandler::validateRange(notional_, "notional") ; ObjectHandler::validateRange(frequency_, "frequency") ; ObjectHandler::validateRange(daycounter_, "daycounter") ; ObjectHandler::validateRange(spread_, "spread") ; // Création des oper ObjectHandler::ConvertOper myOper1(* firstCouponDate_), myOper2(* lastCouponDate_), myOper3(* notional_), myOper4(* frequency_), myOper5(* daycounter_), myOper6(* spread_) ; // création des dates et contrôles sur les dates intermédiaires QuantLib::Date effectiveDate(QuantLib::Date(static_cast<QuantLib::BigInteger>(* effectiveDate_))) ; QuantLib::Date maturityDate(QuantLib::Date(static_cast<QuantLib::BigInteger>(* maturityDate_))) ; QuantLib::Date firstCouponDate(myOper1.missing() ? QuantLib::Date() : QuantLib::Date(static_cast<QuantLib::BigInteger>(myOper1))) ; QuantLib::Date lastCouponDate(myOper2.missing() ? QuantLib::Date() : QuantLib::Date(static_cast<QuantLib::BigInteger>(myOper2))) ; QuantLib::Real notional(myOper3.missing() ? 100.0 : static_cast<QuantLib::Real>(myOper3)) ; QuantLib::Frequency frequency(myOper4.missing() ? QuantLib::Quarterly : ObjectHandler::frequencyFactory()(static_cast<std::string>(myOper4))) ; QuantLib::DayCounter daycounter(myOper5.missing() ? QuantLib::Actual360() : ObjectHandler::daycountFactory()(static_cast<std::string>(myOper5))) ; QuantLib::Spread spread(myOper6.missing() ? 0.0 : static_cast<QuantLib::Spread>(myOper6)) ; // on récupère l'index libor OH_GET_REFERENCE(iborIndexPtr, std::string(indexId_), QuantLibAddin::iborIndexObject, QuantLib::IborIndex) // Construction du value object boost::shared_ptr<QuantLibAddin::ValueObjects::floatLegUnitedStatesValueObject> myLegValueObject( new QuantLibAddin::ValueObjects::floatLegUnitedStatesValueObject(objectID_, true)) ; // instanciation de l'instrument boost::shared_ptr<QuantLibAddin::floatLegUnitedStatesObject> myLegObject( new QuantLibAddin::floatLegUnitedStatesObject(myLegValueObject, effectiveDate, firstCouponDate, lastCouponDate, maturityDate, iborIndexPtr, 2, frequency, daycounter, notional, spread, QuantLib::ModifiedFollowing, QuantLib::ModifiedFollowing, true, true)) ; // stockage de l'objet std::string returnValue = ObjectHandler::RepositoryXL::instance().storeObject(objectID_, myLegObject, true) ; // on force la réécriture static XLOPER returnOper ; ObjectHandler::scalarToOper(returnValue, returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; static XLOPER returnOper ; ObjectHandler::scalarToOper(e.what(), returnOper) ; return & returnOper ; } } ;
SwaptionVolCube1::Cube SwaptionVolCube1::sabrCalibration(const Cube& marketVolCube) const { const std::vector<Time>& optionTimes = marketVolCube.optionTimes(); const std::vector<Time>& swapLengths = marketVolCube.swapLengths(); const std::vector<Date>& optionDates = marketVolCube.optionDates(); const std::vector<Period>& swapTenors = marketVolCube.swapTenors(); Matrix alphas(optionTimes.size(), swapLengths.size(),0.); Matrix betas(alphas); Matrix nus(alphas); Matrix rhos(alphas); Matrix forwards(alphas); Matrix errors(alphas); Matrix maxErrors(alphas); Matrix endCriteria(alphas); const std::vector<Matrix>& tmpMarketVolCube = marketVolCube.points(); std::vector<Real> strikes(strikeSpreads_.size()); std::vector<Real> volatilities(strikeSpreads_.size()); for (Size j=0; j<optionTimes.size(); j++) { for (Size k=0; k<swapLengths.size(); k++) { Rate atmForward = atmStrike(optionDates[j], swapTenors[k]); strikes.clear(); volatilities.clear(); for (Size i=0; i<nStrikes_; i++){ Real strike = atmForward+strikeSpreads_[i]; if(strike>=MINSTRIKE) { strikes.push_back(strike); volatilities.push_back(tmpMarketVolCube[i][j][k]); } } const std::vector<Real>& guess = parametersGuess_.operator()( optionTimes[j], swapLengths[k]); const boost::shared_ptr<SABRInterpolation> sabrInterpolation = boost::shared_ptr<SABRInterpolation>(new SABRInterpolation(strikes.begin(), strikes.end(), volatilities.begin(), optionTimes[j], atmForward, guess[0], guess[1], guess[2], guess[3], isParameterFixed_[0], isParameterFixed_[1], isParameterFixed_[2], isParameterFixed_[3], vegaWeightedSmileFit_, endCriteria_, optMethod_, errorAccept_, useMaxError_, maxGuesses_)); sabrInterpolation->update(); Real rmsError = sabrInterpolation->rmsError(); Real maxError = sabrInterpolation->maxError(); alphas [j][k] = sabrInterpolation->alpha(); betas [j][k] = sabrInterpolation->beta(); nus [j][k] = sabrInterpolation->nu(); rhos [j][k] = sabrInterpolation->rho(); forwards [j][k] = atmForward; errors [j][k] = rmsError; maxErrors [j][k] = maxError; endCriteria[j][k] = sabrInterpolation->endCriteria(); QL_ENSURE(endCriteria[j][k]!=EndCriteria::MaxIterations, "global swaptions calibration failed: " "MaxIterations reached: " << "\n" << "option maturity = " << optionDates[j] << ", \n" << "swap tenor = " << swapTenors[k] << ", \n" << "error = " << io::rate(errors[j][k]) << ", \n" << "max error = " << io::rate(maxErrors[j][k]) << ", \n" << " alpha = " << alphas[j][k] << "n" << " beta = " << betas[j][k] << "\n" << " nu = " << nus[j][k] << "\n" << " rho = " << rhos[j][k] << "\n" ); QL_ENSURE(useMaxError_ ? maxError : rmsError < maxErrorTolerance_, "global swaptions calibration failed: " "option tenor " << optionDates[j] << ", swap tenor " << swapTenors[k] << (useMaxError_ ? ": max error " : ": error") << (useMaxError_ ? maxError : rmsError) << " alpha = " << alphas[j][k] << "n" << " beta = " << betas[j][k] << "\n" << " nu = " << nus[j][k] << "\n" << " rho = " << rhos[j][k] << "\n" << (useMaxError_ ? ": error" : ": max error ") << (useMaxError_ ? rmsError :maxError) ); } } Cube sabrParametersCube(optionDates, swapTenors, optionTimes, swapLengths, 8); sabrParametersCube.setLayer(0, alphas); sabrParametersCube.setLayer(1, betas); sabrParametersCube.setLayer(2, nus); sabrParametersCube.setLayer(3, rhos); sabrParametersCube.setLayer(4, forwards); sabrParametersCube.setLayer(5, errors); sabrParametersCube.setLayer(6, maxErrors); sabrParametersCube.setLayer(7, endCriteria); return sabrParametersCube; }
inline Real SimpleQuote::value() const { QL_ENSURE(isValid(), "invalid SimpleQuote"); return value_; }
Real LastFixingQuote::value() const { QL_ENSURE(isValid(), index_->name() << " has no fixing"); return index_->fixing(referenceDate()); }
// parametric fitted curve DLLEXPORT char * xlInitiateFittedBondDiscountCurve (const char * objectID_ , const xloper * evaluationDate_ , const xloper * settlementDate_ , const xloper * instruments_ , const xloper * quote_ , const char * calendarID_ , const char * fittingMethodID_ , const xloper * bondSelectionRule_, const xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInitiateFittedBondDiscountCurve")); try { QL_ENSURE(! functionCall->calledByFunctionWizard(), ""); // called by wizard ? ObjectHandler::validateRange(trigger_, "trigger" ); // validate range ObjectHandler::validateRange(settlementDate_, "settlement Date" ); ObjectHandler::validateRange(instruments_, "instruments" ); ObjectHandler::validateRange(quote_, "quotes" ); ObjectHandler::validateRange(bondSelectionRule_, "bond selection rule"); ObjectHandler::ConvertOper myOper1(* bondSelectionRule_); // bond selection rule oper QuantLib::bondSelectionRule myRule = // the rule (myOper1.missing() ? QuantLib::activeRule() : ObjectHandler::bondSelectionRuleFactory()( static_cast<std::string>(myOper1))); QuantLib::Calendar curveCalendar // calendar = ObjectHandler::calendarFactory()(calendarID_); ObjectHandler::ConvertOper oper1(* evaluationDate_); // evaluation date QuantLib::Date evaluationDate(oper1.missing() ? QuantLib::Date() : static_cast<QuantLib::Date>(oper1)); std::vector<std::string> instruments = // instrument ids ObjectHandler::operToVector<std::string>( * instruments_, "instruments"); std::vector<QuantLib::Real> quote = // quotes ObjectHandler::operToVector<double>( * quote_, "quote"); std::vector<boost::shared_ptr<QuantLib::BondHelper> > instrumentsObject; // helpers for (unsigned int i = 0 ; i < instruments.size() ; i++) { // capture individual bonds try { OH_GET_REFERENCE(instrumentPtr, // get a reference instruments[i], QuantLibAddin::Bond, QuantLib::Bond) if (quote[i] != 0.0 && instrumentPtr->isTradable()) { // valid quote ? QuantLib::RelinkableHandle<QuantLib::Quote> quoteHandle; // the handler quoteHandle.linkTo(boost::shared_ptr<QuantLib::Quote>( // link to the quote new QuantLib::SimpleQuote(quote[i]))); boost::shared_ptr<QuantLib::BondHelper> noteHelper( // the helper new QuantLib::BondHelper(quoteHandle, instrumentPtr)); instrumentsObject.push_back(noteHelper); // helper storage } } catch (...) {} // nothing on exception } ObjectHandler::ConvertOper oper2(* settlementDate_); // settlement date QuantLib::Date settlementDate(oper2.missing() ? instrumentsObject[0]->bond()->settlementDate(evaluationDate) : static_cast<QuantLib::Date>(oper2)); OH_GET_OBJECT(fittingMethodTemp, // fitting method selection fittingMethodID_, ObjectHandler::Object) std::string returnValue; if (fittingMethodTemp->properties()->className() // svensson ? == "stochasticFittingValueObject") { OH_GET_REFERENCE(fittingMethodPtr, fittingMethodID_, QuantLibAddin::stochasticFittingObject, QuantLib::stochasticFittingHelper) // build the value object boost::shared_ptr<QuantLibAddin::ValueObjects::fittedBondDiscountCurveValueObject> curveValueObject( new QuantLibAddin::ValueObjects::fittedBondDiscountCurveValueObject( objectID_, settlementDate.serialNumber(), true)); boost::shared_ptr<ObjectHandler::Object> myCurve( // instanciating the curve new QuantLibAddin::fittedBondDiscountCurveObject( curveValueObject, settlementDate, myRule.select(instrumentsObject, settlementDate), * fittingMethodPtr->fittingMethod(), fittingMethodPtr->initialVector(), fittingMethodPtr->randomMatrix(), fittingMethodPtr->accuracy(), fittingMethodPtr->maxEvaluationPercycle(), fittingMethodPtr->cyclesPerThread(), fittingMethodPtr->cycles(), 1.000, // simplex lambda true)) ; returnValue = // the value to return ObjectHandler::RepositoryXL::instance().storeObject(objectID_, myCurve , true ); } static char ret[XL_MAX_STR_LEN]; ObjectHandler::stringToChar(returnValue, ret); return ret; } catch (std::exception & e) { static char ret[XL_MAX_STR_LEN]; ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall); ObjectHandler::stringToChar(std::string(e.what()), ret); return ret; } };
/* Fonction de calcul du carry d'un bond */ DLLEXPORT xloper * xlInstrumentCarry (const char * instrumentId_, const double * startAccruedDate_, const double * endAccruedDate_, const double * instrumentYield_, const char * conventionId_, xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInstrumentCarry")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; double returnValue ; // trigger pour provoquer le recalcul ObjectHandler::validateRange(trigger_, "trigger") ; // on récupère la convention OH_GET_REFERENCE(conventionPtr, conventionId_, QuantLibAddin::interestRateConventionObject, QuantLib::InterestRate) // on récupère l'instrument OH_GET_UNDERLYING(myBond, instrumentId_, QuantLibAddin::Bond, QuantLib::Bond) returnValue = myBond.cleanPrice(* instrumentYield_, conventionPtr->dayCounter(), conventionPtr->compounding(), conventionPtr->frequency(), conventionPtr->businessDayConvention(), myBond.settlementDate( QuantLib::Date(static_cast<QuantLib::BigInteger>(* endAccruedDate_)))) ; returnValue -= myBond.cleanPrice(* instrumentYield_, conventionPtr->dayCounter(), conventionPtr->compounding(), conventionPtr->frequency(), conventionPtr->businessDayConvention(), myBond.settlementDate( QuantLib::Date(static_cast<QuantLib::BigInteger>(* startAccruedDate_)))) ; // variable de retour static XLOPER returnOper ; ObjectHandler::scalarToOper(returnValue, returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall); static XLOPER returnOper; returnOper.xltype = xltypeErr; returnOper.val.err = xlerrValue; return & returnOper; } }
// register an interpolated curve object DLLEXPORT char * xlInitiateInterpolatedCurve(const char * objectID_ , xloper * calculationDate_, const char * curveCalendarId_, xloper * helperId_ , xloper * trigger_ ) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInitiateInterpolatedCurve")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; // range validation ObjectHandler::validateRange(trigger_ , "trigger" ); ObjectHandler::validateRange(helperId_ , "helper Id" ); ObjectHandler::validateRange(calculationDate_, "calculation Date"); ObjectHandler::ConvertOper myOper1(* calculationDate_) ; // xlopers std::vector<std::string> helperId = ObjectHandler::operToVector<std::string>( * helperId_, "helper Id") ; QuantLib::Date currentDate( // initiate pricing date myOper1.missing() ? QuantLib::Date() : QuantLib::Date(static_cast<QuantLib::BigInteger>(myOper1))); std::vector<boost::shared_ptr<QuantLib::BootstrapHelper< // the helpers QuantLib::YieldTermStructure> > > helpers; for (std::vector<std::string>::const_iterator It = helperId.begin(); It != helperId.end(); ++It) { OH_GET_REFERENCE(helperPtr, * It, // get helper references QuantLibAddin::RateHelper, QuantLib::RateHelper); helpers.push_back(helperPtr); } // Construction du value object boost::shared_ptr<QuantLibAddin::ValueObjects::interpolatedCurveValueObject> curveValueObject( new QuantLibAddin::ValueObjects::interpolatedCurveValueObject( objectID_, currentDate.serialNumber(), true)) ; // creates the curve boost::shared_ptr<ObjectHandler::Object> myCurve( new QuantLibAddin::interpolatedCurveObject( curveValueObject, currentDate, helpers, true, std::vector<QuantLib::Handle<QuantLib::Quote> >(), // empty jump date std::vector<QuantLib::Date>(), CURVE_DEFAULT_ACCURACY)); // object storage std::string returnValue = ObjectHandler::RepositoryXL::instance().storeObject(objectID_, myCurve, true); static char ret[XL_MAX_STR_LEN] ; ObjectHandler::stringToChar(returnValue, ret); return ret; } catch (std::exception & e) { static char ret[XL_MAX_STR_LEN]; ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall); ObjectHandler::stringToChar(e.what(), ret); return ret; } } ;
FlatVol::FlatVol( const vector<Volatility>& vols, const shared_ptr<PiecewiseConstantCorrelation>& corr, const EvolutionDescription& evolution, Size numberOfFactors, const vector<Rate>& initialRates, const vector<Spread>& displacements) : numberOfFactors_(numberOfFactors), numberOfRates_(initialRates.size()), numberOfSteps_(evolution.evolutionTimes().size()), initialRates_(initialRates), displacements_(displacements), evolution_(evolution), pseudoRoots_(numberOfSteps_, Matrix(numberOfRates_, numberOfFactors_)) { const vector<Time>& rateTimes = evolution.rateTimes(); QL_REQUIRE(numberOfRates_==rateTimes.size()-1, "mismatch between number of rates (" << numberOfRates_ << ") and rate times"); QL_REQUIRE(numberOfRates_==displacements.size(), "mismatch between number of rates (" << numberOfRates_ << ") and displacements (" << displacements.size() << ")"); QL_REQUIRE(numberOfRates_==vols.size(), "mismatch between number of rates (" << numberOfRates_ << ") and vols (" << vols.size() << ")"); QL_REQUIRE(numberOfRates_<=numberOfFactors_*numberOfSteps_, "number of rates (" << numberOfRates_ << ") greater than number of factors (" << numberOfFactors_ << ") times number of steps (" << numberOfSteps_ << ")"); QL_REQUIRE(numberOfFactors<=numberOfRates_, "number of factors (" << numberOfFactors << ") cannot be greater than numberOfRates (" << numberOfRates_ << ")"); QL_REQUIRE(numberOfFactors>0, "number of factors (" << numberOfFactors << ") must be greater than zero"); Time effStopTime = 0.0; const vector<Time>& corrTimes = corr->times(); const vector<Time>& evolTimes = evolution.evolutionTimes(); Matrix covariance(numberOfRates_, numberOfRates_); for (Size k=0, kk=0; k<numberOfSteps_; ++k) { // one covariance per evolution step std::fill(covariance.begin(), covariance.end(), 0.0); // there might be more than one correlation matrix // in a single evolution step for (; corrTimes[kk]<evolTimes[k]; ++kk) { Time effStartTime = effStopTime; effStopTime = corrTimes[kk]; const Matrix& corrMatrix = corr->correlation(kk); for (Size i=0; i<numberOfRates_; ++i) { for (Size j=i; j<numberOfRates_; ++j) { Real cov = flatVolCovariance(effStartTime, effStopTime, rateTimes[i], rateTimes[j], vols[i], vols[j]); covariance[i][j] += cov * corrMatrix[i][j]; } } } // last part in the evolution step Time effStartTime = effStopTime; effStopTime = evolTimes[k]; const Matrix& corrMatrix = corr->correlation(kk); for (Size i=0; i<numberOfRates_; ++i) { for (Size j=i; j<numberOfRates_; ++j) { Real cov = flatVolCovariance(effStartTime, effStopTime, rateTimes[i], rateTimes[j], vols[i], vols[j]); covariance[i][j] += cov * corrMatrix[i][j]; } } // no more use for the kk-th correlation matrix while (kk<corrTimes.size() && corrTimes[kk]<=evolTimes[k]) ++kk; // make it symmetric for (Size i=0; i<numberOfRates_; ++i) { for (Size j=i+1; j<numberOfRates_; ++j) { covariance[j][i] = covariance[i][j]; } } pseudoRoots_[k] = rankReducedSqrt(covariance, numberOfFactors, 1.0, SalvagingAlgorithm::None); QL_ENSURE(pseudoRoots_[k].rows()==numberOfRates_, "step " << k << " flat vol wrong number of rows: " << pseudoRoots_[k].rows() << " instead of " << numberOfRates_); QL_ENSURE(pseudoRoots_[k].columns()==numberOfFactors, "step " << k << " flat vol wrong number of columns: " << pseudoRoots_[k].columns() << " instead of " << numberOfFactors_); } }
/* Fonction de calcul du nombre de flux restant */ DLLEXPORT xloper * xlInstrumentFlowCount (const char * instrumentId_, xloper * settlementDate_, xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlInstrumentFlowCount")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; /* recherche de code erreur */ ObjectHandler::validateRange(trigger_, "trigger") ; ObjectHandler::validateRange(settlementDate_, "settlement Date") ; /* on récupère l'instrument */ OH_GET_UNDERLYING(myBond, instrumentId_, QuantLibAddin::Bond, QuantLib::Bond) /* les XLOPER des date */ ObjectHandler::ConvertOper myOper(* settlementDate_) ; QuantLib::Date settlementDate( myOper.missing() ? QuantLib::Date() : QuantLib::Date(static_cast<QuantLib::BigInteger>(myOper))) ; QuantLib::Natural returnValue = 0; // increments for (std::vector<boost::shared_ptr<QuantLib::CashFlow> >::const_reverse_iterator It = myBond.cashflows().crbegin(); It != myBond.cashflows().crend(); It++) It->get()->date() > settlementDate ? returnValue++ : 0; static XLOPER returnOper ; ObjectHandler::scalarToOper(static_cast<double>(returnValue), returnOper) ; return & returnOper ; } catch (std::exception & e) { #ifdef _DEBUG OutputDebugString(e.what()) ; #endif ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; static XLOPER returnOper ; returnOper.xltype = xltypeErr ; returnOper.val.err = xlerrValue ; return & returnOper ; } } ;
/* Fonction de calcul de la NPV d'un swap ou d'une jambe */ DLLEXPORT xloper * xlSwapNPV (const char * instrumentId_, const char * discountCurveId_, xloper * forwardCurveId_, xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlSwapNPV")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; // validation ObjectHandler::validateRange(trigger_, "trigger") ; ObjectHandler::validateRange(forwardCurveId_, "forward Curve") ; // conversion des xloper ObjectHandler::ConvertOper myOper(* forwardCurveId_) ; // on récupère la courbe de discounting OH_GET_OBJECT(discountCurvePtr, discountCurveId_, ObjectHandler::Object) QuantLib::Handle<QuantLib::YieldTermStructure> discountCurveHandler = QuantLibAddin::CoerceHandle<QuantLibAddin::YieldTermStructure, QuantLib::YieldTermStructure>()(discountCurvePtr) ; // on récupère l'instrument OH_GET_REFERENCE(mySwap, instrumentId_, QuantLibAddin::interestRateSwapObject, QuantLib::vanillaSwap2) boost::shared_ptr<QuantLib::PricingEngine> myPricingEngine ; // ligature du pricing engine if (myOper.missing()) { myPricingEngine = boost::shared_ptr<QuantLib::PricingEngine>( new QuantLib::DiscountingSwapEngine(discountCurveHandler/*, discountCurveHandler*/)) ; //mySwap->setFixingIndex(* discountCurveHandler) ; } else { // on récupère la courbe forward OH_GET_OBJECT(forwardCurvePtr, static_cast<std::string>(myOper), ObjectHandler::Object) QuantLib::Handle<QuantLib::YieldTermStructure> forwardCurveHandler = QuantLibAddin::CoerceHandle<QuantLibAddin::YieldTermStructure, QuantLib::YieldTermStructure>()(forwardCurvePtr) ; myPricingEngine = boost::shared_ptr<QuantLib::PricingEngine>( new QuantLib::DiscountingSwapEngine(discountCurveHandler/*, forwardCurveHandler*/)) ; //mySwap->setFixingIndex(* forwardCurveHandler) ; } mySwap->setPricingEngine(myPricingEngine) ; static XLOPER returnOper ; ObjectHandler::scalarToOper(mySwap->NPV(), returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; static XLOPER returnOper ; ObjectHandler::scalarToOper(e.what(), returnOper) ; return & returnOper ; } } ;
/* fonction de calcul de la matrice de variance-covariance d'un historique de taux */ DLLEXPORT xloper * xlCovarianceMatrixEWMA(const xloper * seriesId_, const double * decay_, const double * startDate_, const bool * norm_, const xloper * trigger_) { boost::shared_ptr<ObjectHandler::FunctionCall> functionCall( new ObjectHandler::FunctionCall("xlCovarianceMatrixEWMA")) ; try { QL_ENSURE(! functionCall->calledByFunctionWizard(), "") ; /* déclaration du trigger */ ObjectHandler::validateRange(trigger_, "trigger") ; /* conversion des xloper */ std::vector<std::string> seriesId = ObjectHandler::operToVector<std::string>(* seriesId_, "seriesId") ; /* contrôle sur les dimensions */ QL_ENSURE(seriesId.size() >= 2, "unconsistent data set") ; /* on récupére les séries variationnelles */ std::vector<QuantLib::TimeSeries<double> > timeSeriesVector ; for (std::vector<std::string>::const_iterator It = seriesId.begin() ; It != seriesId.end() ; ++It) { OH_GET_REFERENCE(TimeSeriesPtr, * It, QuantLibAddin::TimeSeriesObject<double>, QuantLib::TimeSeries<double>) timeSeriesVector.push_back(* TimeSeriesPtr) ; } std::vector<QuantLib::TimeSeries<double> > nTimeSeriesVector ; /* selon le mode choisi */ if (* norm_ == true) { std::vector<QuantLib::TimeSeries<double> > deltaSeriesVector ; for (unsigned long i = 0 ; i < timeSeriesVector.size() ; i++) deltaSeriesVector.push_back( QuantLib::deltaTimeSeries<double>(timeSeriesVector[i])) ; /* création des vecteurs moyenne et std dev */ std::vector<double> mean ; std::vector<double> variance ; for (std::vector<QuantLib::TimeSeries<double> >::const_iterator It = deltaSeriesVector.begin() ; It < deltaSeriesVector.end() ; ++It) { variance.push_back(covarianceEWMA(* It, * It, QuantLib::Date(static_cast<QuantLib::BigInteger>(* startDate_)), decay_)) ; mean.push_back(meanEWMA(* It, QuantLib::Date(static_cast<QuantLib::BigInteger>(* startDate_)), decay_)) ; } /* Mode normé */ for (unsigned int i = 0 ; i < deltaSeriesVector.size() ; i++) { std::vector<double> tempValues ; std::vector<QuantLib::Date> tempDates ; for (QuantLib::TimeSeries<double>::const_iterator It = deltaSeriesVector[i].begin() ; It != deltaSeriesVector[i].end() ; ++It) { tempDates.push_back(It->first) ; tempValues.push_back((deltaSeriesVector[i][It->first] - mean[i]) / pow((deltaSeriesVector[i].size() + 1) * variance[i], 0.5)) ; } QuantLib::TimeSeries<double> tempSeries(tempDates.begin(), tempDates.end(), tempValues.begin()) ; nTimeSeriesVector.push_back(tempSeries) ; } } else { /* Mode non normé */ std::vector<double> mean ; for (std::vector<QuantLib::TimeSeries<double>>::const_iterator It = timeSeriesVector.begin() ; It < timeSeriesVector.end() ; ++It) mean.push_back(meanEWMA(* It, QuantLib::Date( static_cast<QuantLib::BigInteger>(* startDate_)), decay_)) ; /* on se contente de centrer les séries */ for (unsigned int i = 0 ; i < timeSeriesVector.size() ; i++) { std::vector<double> tempValues ; std::vector<QuantLib::Date> tempDates ; for (QuantLib::TimeSeries<double>::const_iterator It = timeSeriesVector[i].begin() ; It != timeSeriesVector[i].end() ; ++It) { tempDates.push_back(It->first) ; tempValues.push_back(timeSeriesVector[i][It->first] - mean[i]) ; } QuantLib::TimeSeries<double> tempSeries(tempDates.begin(), tempDates.end(), tempValues.begin()) ; nTimeSeriesVector.push_back(tempSeries) ; } } /* création de la matrice de retour */ QuantLib::Matrix returnMatrix( nTimeSeriesVector.size(), nTimeSeriesVector.size()) ; for (unsigned int i = 0 ; i < nTimeSeriesVector.size() ; i++) { for (unsigned int j = 0 ; j <= i ; j++) { returnMatrix[i][j] = covarianceEWMA(nTimeSeriesVector[i], nTimeSeriesVector[j], QuantLib::Date(static_cast<QuantLib::BigInteger>(* startDate_)), decay_) ; returnMatrix[j][i] = returnMatrix[i][j]; } } static OPER returnOper ; ObjectHandler::MatrixToOper(returnMatrix, returnOper) ; return & returnOper ; } catch (std::exception & e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall) ; return 0 ; } }
void BinomialBarrierEngine<T,D>::calculate() const { DayCounter rfdc = process_->riskFreeRate()->dayCounter(); DayCounter divdc = process_->dividendYield()->dayCounter(); DayCounter voldc = process_->blackVolatility()->dayCounter(); Calendar volcal = process_->blackVolatility()->calendar(); Real s0 = process_->stateVariable()->value(); QL_REQUIRE(s0 > 0.0, "negative or null underlying given"); Volatility v = process_->blackVolatility()->blackVol( arguments_.exercise->lastDate(), s0); Date maturityDate = arguments_.exercise->lastDate(); Rate r = process_->riskFreeRate()->zeroRate(maturityDate, rfdc, Continuous, NoFrequency); Rate q = process_->dividendYield()->zeroRate(maturityDate, divdc, Continuous, NoFrequency); Date referenceDate = process_->riskFreeRate()->referenceDate(); // binomial trees with constant coefficient Handle<YieldTermStructure> flatRiskFree( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, r, rfdc))); Handle<YieldTermStructure> flatDividends( boost::shared_ptr<YieldTermStructure>( new FlatForward(referenceDate, q, divdc))); Handle<BlackVolTermStructure> flatVol( boost::shared_ptr<BlackVolTermStructure>( new BlackConstantVol(referenceDate, volcal, v, voldc))); boost::shared_ptr<StrikedTypePayoff> payoff = boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-striked payoff given"); Time maturity = rfdc.yearFraction(referenceDate, maturityDate); boost::shared_ptr<StochasticProcess1D> bs( new GeneralizedBlackScholesProcess( process_->stateVariable(), flatDividends, flatRiskFree, flatVol)); // correct timesteps to ensure a (local) minimum, using Boyle and Lau // approach. See Journal of Derivatives, 1/1994, // "Bumping up against the barrier with the binomial method" // Note: this approach works only for CoxRossRubinstein lattices, so // is disabled if T is not a CoxRossRubinstein or derived from it. Size optimum_steps = timeSteps_; if (boost::is_base_of<CoxRossRubinstein, T>::value && maxTimeSteps_ > timeSteps_ && s0 > 0 && arguments_.barrier > 0) { Real divisor; if (s0 > arguments_.barrier) divisor = std::pow(std::log(s0 / arguments_.barrier), 2); else divisor = std::pow(std::log(arguments_.barrier / s0), 2); if (!close(divisor,0)) { for (Size i=1; i < timeSteps_ ; ++i) { Size optimum = Size(( i*i * v*v * maturity) / divisor); if (timeSteps_ < optimum) { optimum_steps = optimum; break; // found first minimum with iterations>=timesteps } } } if (optimum_steps > maxTimeSteps_) optimum_steps = maxTimeSteps_; // too high, limit } TimeGrid grid(maturity, optimum_steps); boost::shared_ptr<T> tree(new T(bs, maturity, optimum_steps, payoff->strike())); boost::shared_ptr<BlackScholesLattice<T> > lattice( new BlackScholesLattice<T>(tree, r, maturity, optimum_steps)); D option(arguments_, *process_, grid); option.initialize(lattice, maturity); // Partial derivatives calculated from various points in the // binomial tree // (see J.C.Hull, "Options, Futures and other derivatives", 6th edition, pp 397/398) // Rollback to third-last step, and get underlying prices (s2) & // option values (p2) at this point option.rollback(grid[2]); Array va2(option.values()); QL_ENSURE(va2.size() == 3, "Expect 3 nodes in grid at second step"); Real p2u = va2[2]; // up Real p2m = va2[1]; // mid Real p2d = va2[0]; // down (low) Real s2u = lattice->underlying(2, 2); // up price Real s2m = lattice->underlying(2, 1); // middle price Real s2d = lattice->underlying(2, 0); // down (low) price // calculate gamma by taking the first derivate of the two deltas Real delta2u = (p2u - p2m)/(s2u-s2m); Real delta2d = (p2m-p2d)/(s2m-s2d); Real gamma = (delta2u - delta2d) / ((s2u-s2d)/2); // Rollback to second-last step, and get option values (p1) at // this point option.rollback(grid[1]); Array va(option.values()); QL_ENSURE(va.size() == 2, "Expect 2 nodes in grid at first step"); Real p1u = va[1]; Real p1d = va[0]; Real s1u = lattice->underlying(1, 1); // up (high) price Real s1d = lattice->underlying(1, 0); // down (low) price Real delta = (p1u - p1d) / (s1u - s1d); // Finally, rollback to t=0 option.rollback(0.0); Real p0 = option.presentValue(); // Store results results_.value = p0; results_.delta = delta; results_.gamma = gamma; // theta can be approximated by calculating the numerical derivative // between mid value at third-last step and at t0. The underlying price // is the same, only time varies. results_.theta = (p2m - p0) / grid[2]; }