inline Real ReplicatingVarianceSwapEngine::computeReplicatingPortfolio( const weights_type& optionWeights) const { boost::shared_ptr<Exercise> exercise( new EuropeanExercise(arguments_.maturityDate)); boost::shared_ptr<PricingEngine> optionEngine( new AnalyticEuropeanEngine(process_)); Real optionsValue = 0.0; for (weights_type::const_iterator i = optionWeights.begin(); i < optionWeights.end(); ++i) { boost::shared_ptr<StrikedTypePayoff> payoff = i->first; EuropeanOption option(payoff, exercise); option.setPricingEngine(optionEngine); Real weight = i->second; optionsValue += option.NPV() * weight; } Real f = optionWeights.front().first->strike(); return 2.0 * riskFreeRate() - 2.0/residualTime() * (((underlying()/riskFreeDiscount() - f)/f) + std::log(f/underlying())) + optionsValue/riskFreeDiscount(); }
Real AnalyticBarrierEngine::B(Real phi) const { Real x2 = std::log(underlying()/barrier())/stdDeviation() + muSigma(); Real N1 = f_(phi*x2); Real N2 = f_(phi*(x2-stdDeviation())); return phi*(underlying() * dividendDiscount() * N1 - strike() * riskFreeDiscount() * N2); }
Real AnalyticBarrierEngine::D(Real eta, Real phi) const { Real HS = barrier()/underlying(); Real powHS0 = std::pow(HS, 2 * mu()); Real powHS1 = powHS0 * HS * HS; Real y2 = std::log(barrier()/underlying())/stdDeviation() + muSigma(); Real N1 = f_(eta*y2); Real N2 = f_(eta*(y2-stdDeviation())); return phi*(underlying() * dividendDiscount() * powHS1 * N1 - strike() * riskFreeDiscount() * powHS0 * N2); }
Real AnalyticBarrierEngine::E(Real eta) const { if (rebate() > 0) { Real powHS0 = std::pow(barrier()/underlying(), 2 * mu()); Real x2 = std::log(underlying()/barrier())/stdDeviation() + muSigma(); Real y2 = std::log(barrier()/underlying())/stdDeviation() + muSigma(); Real N1 = f_(eta*(x2 - stdDeviation())); Real N2 = f_(eta*(y2 - stdDeviation())); return rebate() * riskFreeDiscount() * (N1 - powHS0 * N2); } else { return 0.0; } }
/** * Apply the sketching transform on A and write to sketch_of_A. * Implementation for columnwise. */ void apply_impl(const matrix_type& A, output_matrix_type& sketch_of_A, skylark::sketch::columnwise_tag tag) const { // TODO verify sizes etc. underlying_t underlying(*data_type::_underlying_data); underlying.apply(A, sketch_of_A, tag); # if SKYLARK_HAVE_OPENMP # pragma omp parallel for collapse(2) # endif for(int j = 0; j < base::Width(A); j++) for(int i = 0; i < data_type::_S; i++) { value_type x = sketch_of_A.Get(i, j); x += data_type::_shifts[i]; # ifndef SKYLARK_INEXACT_COSINE x = std::cos(x); # else // x = std::cos(x) is slow // Instead use low-accuracy approximation if (x < -3.14159265) x += 6.28318531; else if (x > 3.14159265) x -= 6.28318531; x += 1.57079632; if (x > 3.14159265) x -= 6.28318531; x = (x < 0) ? 1.27323954 * x + 0.405284735 * x * x : 1.27323954 * x - 0.405284735 * x * x; # endif x = data_type::_outscale * x; sketch_of_A.Set(i, j, x); } }
Real AnalyticContinuousFloatingLookbackEngine::A(Real eta) const { Volatility vol = volatility(); Real lambda = 2.0*(riskFreeRate() - dividendYield())/(vol*vol); Real s = underlying()/minmax(); Real d1 = std::log(s)/stdDeviation() + 0.5*(lambda+1.0)*stdDeviation(); Real n1 = f_(eta*d1); Real n2 = f_(eta*(d1-stdDeviation())); Real n3 = f_(eta*(-d1+lambda*stdDeviation())); Real n4 = f_(eta*-d1); Real pow_s = std::pow(s, -lambda); return eta*((underlying() * dividendDiscount() * n1 - minmax() * riskFreeDiscount() * n2) + (underlying() * riskFreeDiscount() * (pow_s * n3 - dividendDiscount()* n4/riskFreeDiscount())/ lambda)); }
void apply (const matrix_type& A, output_matrix_type& sketch_of_A, Dimension dimension) const { try { // TODO verify sizes etc. underlying_t underlying(*data_type::_underlying_data); underlying.apply(A, sketch_of_A, dimension); # if SKYLARK_HAVE_OPENMP # pragma omp parallel for collapse(2) # endif for(int j = 0; j < base::Width(sketch_of_A); j++) for(int i = 0; i < base::Height(sketch_of_A); i++) { value_type val = sketch_of_A.Get(i, j); sketch_of_A.Set(i, j, data_type::_outscale * std::exp(-val)); } } catch (std::logic_error e) { SKYLARK_THROW_EXCEPTION ( base::elemental_exception() << base::error_msg(e.what()) ); } catch(boost::mpi::exception e) { SKYLARK_THROW_EXCEPTION ( base::mpi_exception() << base::error_msg(e.what()) ); } }
Real AnalyticDoubleBarrierEngine::putKO() const { Real mu1 = 2 * costOfCarry() / volatilitySquared() + 1; Real bsigma = (costOfCarry() + volatilitySquared() / 2.0) * residualTime() / stdDeviation(); Real acc1 = 0; Real acc2 = 0; for (int n = -series_ ; n <= series_ ; ++n) { Real L2n = std::pow(barrierLo(), 2 * n); Real U2n = std::pow(barrierHi(), 2 * n); Real y1 = std::log( underlying()* U2n / (std::pow(barrierLo(), 2 * n + 1)) ) / stdDeviation() + bsigma; Real y2 = std::log( underlying()* U2n / (strike() * L2n) ) / stdDeviation() + bsigma; Real y3 = std::log( std::pow(barrierLo(), 2 * n + 2) / (barrierLo() * underlying() * U2n) ) / stdDeviation() + bsigma; Real y4 = std::log( std::pow(barrierLo(), 2 * n + 2) / (strike() * underlying() * U2n) ) / stdDeviation() + bsigma; acc1 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1-2) * (f_(y1 - stdDeviation()) - f_(y2 - stdDeviation())) - std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1-2 ) * (f_(y3-stdDeviation()) - f_(y4-stdDeviation())); acc2 += std::pow( std::pow(barrierHi(), n) / std::pow(barrierLo(), n), mu1 ) * (f_(y1) - f_(y2)) - std::pow( std::pow(barrierLo(), n+1) / (std::pow(barrierHi(), n) * underlying()), mu1 ) * (f_(y3) - f_(y4)); } Real rend = std::exp(-dividendYield() * residualTime()); Real kov = strike() * riskFreeDiscount() * acc1 - underlying() * rend * acc2; return std::max(0.0, kov); }
Real AnalyticDoubleBarrierEngine::vanillaEquivalent() const { // Call KI equates to vanilla - callKO boost::shared_ptr<StrikedTypePayoff> payoff = boost::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff); Real forwardPrice = underlying() * dividendDiscount() / riskFreeDiscount(); BlackCalculator black(payoff, forwardPrice, stdDeviation(), riskFreeDiscount()); Real vanilla = black.value(); if (vanilla < 0.0) vanilla = 0.0; return vanilla; }
Real AnalyticBarrierEngine::F(Real eta) const { if (rebate() > 0) { Rate m = mu(); Volatility vol = volatility(); Real lambda = std::sqrt(m*m + 2.0*riskFreeRate()/(vol * vol)); Real HS = barrier()/underlying(); Real powHSplus = std::pow(HS, m + lambda); Real powHSminus = std::pow(HS, m - lambda); Real sigmaSqrtT = stdDeviation(); Real z = std::log(barrier()/underlying())/sigmaSqrtT + lambda * sigmaSqrtT; Real N1 = f_(eta * z); Real N2 = f_(eta * (z - 2.0 * lambda * sigmaSqrtT)); return rebate() * (powHSplus * N1 + powHSminus * N2); } else { return 0.0; } }
int ConfigObjectLoader::toInt( expr_cref value ) const { expr_cref expr = underlying( value ); // If we want an int it has to be that. Not a double. if( expr.type() != EInt ) { std::ostringstream oss; oss << "expected int, got " << expr.value() << " interpreted as " << typestr[expr.type()]; throw TypeError( oss.str() ); } return boost::lexical_cast<int>( expr.value() ); }
double ConfigObjectLoader::toDouble( expr_cref value ) const { expr_cref expr = underlying( value ); // we want a double. If we get an int, that will suffice. All ints are also doubles. if( expr.type() != EReal && expr.type() != EInt ) { std::ostringstream oss; oss << "expected a number, got " << expr.value() << " interpreted as " << typestr[expr.type()]; throw TypeError( oss.str() ); } return boost::lexical_cast<double>( expr.value() ); }
bool ConfigObjectLoader::toBool( expr_cref value ) const { expr_cref expr = underlying( value ); if( expr.type() != EBool ) { std::ostringstream oss; oss << "expected boolean, got " << expr.value() << " interpreted as " << typestr[expr.type()] << " (note, numbers do not convert to booleans)"; throw TypeError( oss.str() ); } return ( expr.value() == "true" ); // there are stored as "true" and "false". Anything else would not be interpreted as boolean }
std::string ConfigObjectLoader::toEnum( IOC::expr_cref value ) const { std::string last; expr_cref expr = underlying( value, &last, false ); if( expr.type() != EVariable ) { std::ostringstream oss; oss << last << " has been defined to " << expr.value() << " of type " << typestr[expr.type()] << " expecting an enumeration"; throw TypeError( oss.str() ); } return last; // which should be the same as expr.value() }
void ConfigObjectLoader::toVector( expr_cref value, std::vector< RecursiveExpressionPtr > & res ) const { // this is actually fairly straightforward // once again traverse down through any variables expr_cref expr = underlying( value ); // it must be expressed as List. if( expr.type() != EList ) { std::ostringstream oss; oss << "expected a list, got " << expr.value() << " interpreted as " << typestr[expr.type()]; throw TypeError( oss.str() ); } // now just populate it res = expr.params(); }
ObjectInfoPtr ConfigObjectLoader::getObjectInfo( expr_cref expr, str_cref name ) const { if( !name.empty() ) { ObjectInfoPtr obj; // already found. if( Utility::mapLookup( m_objects, name, obj ) ) { return obj; } } if( expr.type() == EObject ) // it's an object expression { std::string className = expr.value(); ClassInfoPtr classInfo = getClassInfo( className ); BuilderPtr builder = classInfo->createBuilder( name, expr ); ObjectInfoPtr obj( new ObjectInfo( name, expr, *classInfo, builder ) ); // It needs to be in the map before we bind its parameters so a circular reference can be detected m_objects[name] = obj; builder->bindParams( *this ); return obj; } else if( expr.type() == EVariable ) { // this could recurse indefinitely with circular reference.. // NOTE: if anything throws here, let ParamBinderBase manage the context of the error. std::string objName; expr_cref expr2 = underlying( expr, &objName ); return getObjectInfo( expr2, objName ); } else // this isn't a class. It might be a map or list or whatever but isn't an object { std::ostringstream oss; oss << expr.value() << " is not an object"; // Do not throw TypeError here. If it isn't an object it can't be a proxy either throw std::invalid_argument( oss.str() ); } }
// To return an actual std::map at this stage would be far too complex. We returns a vector of pairs // which will then be void ConfigObjectLoader::toMap( expr_cref value, std::vector< std::pair< RecursiveExpressionPtr, RecursiveExpressionPtr > > & res ) const { expr_cref expr = underlying( value ); if( expr.type() != EMap ) { std::ostringstream oss; oss << "expected a map, got " << expr.value() << " interpreted as " << typestr[expr.type()] << " (note: a List of Pair items is not a map)"; throw TypeError( oss.str() ); } std::vector<RecursiveExpressionPtr> const& params = expr.params(); res.resize( params.size() ); std::transform( params.begin(), params.end(), res.begin(), PairConverter( this ) ); }
size_t ConfigObjectLoader::toUInt( expr_cref value ) const { expr_cref expr = underlying( value ); if( expr.type() != EInt ) { std::ostringstream oss; oss << "expected unsigned int, got " << expr.value() << " interpreted as " << typestr[expr.type()]; throw TypeError( oss.str() ); } try { return boost::lexical_cast<size_t>( expr.value() ); } catch( std::exception const& ) // in case it's a negative number in which case I assume it won't cast { // I want to throw my own exception. std::ostringstream oss; oss << "Expected unsigned int, got " << expr.value() << " Which did not convert (is it negative?)"; throw std::invalid_argument( oss.str() ); } }
/** * Apply the sketching transform that is described in by the sketch_of_A. * Implementation for columnwise. */ void apply_impl(const matrix_type& A, output_matrix_type& sketch_of_A, skylark::sketch::columnwise_tag tag) const { underlying_t underlying(*data_type::_underlying_data); underlying.apply(A, sketch_of_A, tag); El::Matrix<value_type> &SAl = sketch_of_A.Matrix(); size_t col_shift = sketch_of_A.ColShift(); size_t col_stride = sketch_of_A.ColStride(); # if SKYLARK_HAVE_OPENMP # pragma omp parallel for collapse(2) # endif for(size_t j = 0; j < base::Width(SAl); j++) for(size_t i = 0; i < base::Height(SAl); i++) { value_type x = SAl.Get(i, j); x += data_type::_shifts[col_shift + i * col_stride]; # ifndef SKYLARK_INEXACT_COSINE x = std::cos(x); # else // x = std::cos(x) is slow // Instead use low-accuracy approximation if (x < -3.14159265) x += 6.28318531; else if (x > 3.14159265) x -= 6.28318531; x += 1.57079632; if (x > 3.14159265) x -= 6.28318531; x = (x < 0) ? 1.27323954 * x + 0.405284735 * x * x : 1.27323954 * x - 0.405284735 * x * x; # endif x = data_type::_outscale * x; SAl.Set(i, j, x); } }
// For string it is more complex as we have to handle Concat expressions too std::string ConfigObjectLoader::toString( expr_cref value ) const { expr_cref expr = underlying( value ); if( expr.type() == EString ) { return expr.value(); } else if( expr.type() == EConcat ) { std::vector< RecursiveExpressionPtr > const& params = expr.params(); std::string res; for( RecursiveExpressionPtr pexp : params ) { res.append( toString( *pexp ) ); } return res; } else { std::ostringstream oss; oss << "Could not interpret " << expr.value() << " as a string: interpreted as " << typestr[expr.type()]; throw TypeError( oss.str() ); } }
U underlying_cast(T const& v) { return static_cast<U>(underlying(v)); }
void AnalyticDoubleBarrierEngine::calculate() const { QL_REQUIRE(arguments_.exercise->type() == Exercise::European, "this engine handles only european options"); boost::shared_ptr<PlainVanillaPayoff> payoff = boost::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff); QL_REQUIRE(payoff, "non-plain payoff given"); Real strike = payoff->strike(); QL_REQUIRE(strike>0.0, "strike must be positive"); Real spot = underlying(); QL_REQUIRE(spot >= 0.0, "negative or null underlying given"); QL_REQUIRE(!triggered(spot), "barrier(s) already touched"); DoubleBarrier::Type barrierType = arguments_.barrierType; if (triggered(spot)) { if (barrierType == DoubleBarrier::KnockIn) results_.value = vanillaEquivalent(); // knocked in else results_.value = 0.0; // knocked out } else { switch (payoff->optionType()) { case Option::Call: switch (barrierType) { case DoubleBarrier::KnockIn: results_.value = callKI(); break; case DoubleBarrier::KnockOut: results_.value = callKO(); break; case DoubleBarrier::KIKO: case DoubleBarrier::KOKI: QL_FAIL("unsupported double-barrier type: " << barrierType); default: QL_FAIL("unknown double-barrier type: " << barrierType); } break; case Option::Put: switch (barrierType) { case DoubleBarrier::KnockIn: results_.value = putKI(); break; case DoubleBarrier::KnockOut: results_.value = putKO(); break; case DoubleBarrier::KIKO: case DoubleBarrier::KOKI: QL_FAIL("unsupported double-barrier type: " << barrierType); default: QL_FAIL("unknown double-barrier type: " << barrierType); } break; default: QL_FAIL("unknown type"); } } }
std::basic_ostream<Ch, Tr> & operator<<(std::basic_ostream<Ch, Tr> & o, std::stack<T, C> const & s) { return o << underlying(s); }
std::basic_ostream<Ch, Tr> & operator<<(std::basic_ostream<Ch, Tr> & o, std::priority_queue<T, C, P> const & q) { return o << underlying(q); }
/// F flags2 = F{Opt::MoveArms}; /// F flags3 = flags2; /// F flags = ( flags1 | flags2 ) & flags3; /// // flags == flags2 /// /// // ... /// startBehavior(flags); /// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ /// /// HasUnderlying<BitmaskType> Type template <typename Type> class Flags { public: using type = Type; using underlying_type = traits::Decay<decltype(underlying(std::declval<Type>()))>; private: explicit Flags(underlying_type value) : _value(value) {} public: // Regular: Flags() : _value{} {} QI_GENERATE_FRIEND_REGULAR_OPS_1(Flags, _value) // HasUnderlying: