2 votos

Utilizando el enfoque del árbol binomial para calcular el precio de una opción en quantlib - con el tiempo expresado como una fracción del año

Con fines de aprendizaje, estoy intentando precio, con quantlib, una opción europea utilizando el enfoque del árbol de Cox-Ross-Rubinstein.

Algunos ejemplos se proporcionan en el archivo EquityOption.cpp que es parte de la biblioteca.

Sin embargo, me gustaría tasarla, sin utilizar fechas (es decir, sin ninguna convención de día, calendario, fecha de vencimiento ...) sino utilizando solamente una fracción de año como vencimiento (por ejemplo: con T = 0.5).

Hasta donde he leído, todos los ejemplos solo consideran el caso con fechas expresadas como fechas "reales" (por ejemplo: 11/01/2016) y no expresadas como tiempo hasta el vencimiento (por ejemplo: T= 0.1), es decir, el caso estándar de libro de texto.

Dado que la biblioteca se basa en gran medida en motores, y que esos motores están diseñados principalmente con fechas, tengo algunas dificultades para prescindir de las fechas.

Para la fórmula analítica de BS, es fácil ya que el núcleo del motor se basa en el BlackScholesCalculator que es independiente de las fechas (ver un ejemplo completo aquí).

Sin embargo, para el caso binomial, no existe una rutina independiente de fechas (no existe BinomialCalculator..), y la clase DiscretizedVanillaOption requiere una variable del motor como entrada para instanciarlo.

Una solución plausible que se me ocurrió es encontrar dos fechas "falsas", jugando con una pseudo función de .yearFraction(FechaInicioFalsa, FechaFinFalsa); para encontrar dos fechas óptimas que coincidan con la fracción que deseo. Luego usar estas dos fechas para calcular el precio. Sin embargo, esta estrategia parece bastante engorrosa para una solicitud tan simple.

¿Cómo puedo calcular el valor de una opción utilizando el enfoque binomial con un vencimiento expresado como una fracción de año en quantlib?

Por favor, vea a continuación lo que he hecho hasta ahora, estoy atascado en la línea que instancia el DiscretizedVanillaOption.

    Calendar calendar      = NullCalendar();             
    DayCounter dayCounter  = SimpleDayCounter();
    Date t0(1);     
    Option::Type type = Option::Put;
    Real S0 = spot_;
    Real K = strike_;
    Spread q =  dividendYield_;
    Rate r = interestRate_;
    Volatility sigma = volatility_;

    Settings::instance().evaluationDate() = t0;
    Handle underlyingH((boost::static_pointer_cast(boost::make_shared(S0))));
    Handle flatDividendTS((boost::static_pointer_cast(boost::make_shared(t0, q, dayCounter))));
    Handle flatTermStructure((boost::static_pointer_cast(boost::make_shared(t0, r, dayCounter))));
    Handle flatVolTS((boost::static_pointer_cast(boost::make_shared(t0, calendar, sigma, dayCounter))));
    boost::shared_ptr bsmProcess(new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS));
    boost::shared_ptr payoff(new PlainVanillaPayoff(type, K));

    Size timeSteps_ = 200;
    Time maturity = 0.2;
    TimeGrid grid(maturity, timeSteps_);    
    boost::shared_ptr tree(new CoxRossRubinstein(bsmProcess, maturity, timeSteps_,  payoff->strike()));
    boost::shared_ptr > lattice( new BlackScholesLattice(tree, r, maturity, timeSteps_));

    DiscretizedVanillaOption option(/* ????*/,bsmProcess, grid);//<--------- Primer argumento Aquí ?

    option.initialize(lattice, maturity);
    double price = option.presentValue();

4voto

Brad Tutterow Puntos 5628

Me temo que tendrás que utilizar fechas falsas, como mencionaste.

Para facilitar el proceso, puedes utilizar un contador de días con una fórmula simple como Act/360. Dada una fecha de inicio, será más fácil determinar la fecha de finalización correspondiente (startDate+36 para T=0.1, startDate+180 para T=0.5 y así sucesivamente) sin tener que jugar con candidatos.

0 votos

Gracias, sin embargo esto implica una precisión máxima de 1/360 mientras que el modelo teórico no la impone.

0 votos

Sí y no. Las fechas en realidad se ajustan a los nodos del TimeGrid pasado antes del cálculo, así que deberías estar bien. (Puedes ver la implementación del constructor de DiscretizedVanillaOption para más detalles.)

2voto

Nick Klauer Puntos 2837

Finalmente, gracias a la respuesta de Luigi y observando los ejemplos en el testsuite he logrado lograrlo. La fecha de inicio falsa se establece en la fecha de hoy y la fecha de ejercicio es la siguiente :

 Date exDate = today + Integer(timeToMaturity_*360+0.5);

A continuación se muestra un ejemplo de trabajo para el precio de una opción americana con CRR :

double American_CoxRossRubinstein_T(bool IsCall /*si es falso= put*/,
                                    double underlying_,
                                    double strike_,
                                    double riskfree_,
                                    double volatility_,
                                    double dividendYield_,
                                    double timeToMaturity_)
{
    /*----------------------------------------------------*/
    Option::Type optionType =IsCall ? Option::Call : Option::Put ;
    QuantLib::Date today = QuantLib::Date::todaysDate();
    QuantLib::Settings::instance().evaluationDate() = today;
    QuantLib::DayCounter dayCounter = QuantLib::Actual360();
    Calendar calendar  = NullCalendar(); 
    Date exDate = today + Integer(timeToMaturity_*360+0.5);
    Handle underlyingH((boost::static_pointer_cast(boost::make_shared(underlying_))));
    Handle flatDividendTS((boost::static_pointer_cast(boost::make_shared(today, dividendYield_, dayCounter))));
    Handle flatTermStructure((boost::static_pointer_cast(boost::make_shared(today,riskfree_, dayCounter))));
    Handle flatVolTS((boost::static_pointer_cast(boost::make_shared(today, calendar, volatility_, dayCounter))));
    boost::shared_ptr americanExercise(new AmericanExercise(today, exDate));
    boost::shared_ptr payoff(new PlainVanillaPayoff(optionType, strike_));
    VanillaOption americanOption(payoff, americanExercise);
    boost::shared_ptr bsmProcess(new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS));
    Size timeSteps = static_cast(std::max(700 * timeToMaturity_, 20.0));
    americanOption.setPricingEngine(boost::static_pointer_cast(boost::make_shared>(bsmProcess, timeSteps )));
    Real OptionPrice = americanOption.NPV();
    std::cout << std::setprecision(9) << "American_CoxRossRubinstein_T = " << OptionPrice << std::endl;
    return OptionPrice;
}

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X