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 establecer el precio, con quantlib, de una opción europea utilizando el enfoque del árbol Cox-Ross-Rubinstein.

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

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

Hasta donde he leído, todos los ejemplos consideran únicamente 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 depende en gran medida de motores, y que esos motores están diseñados principalmente con fechas, tengo algunas dificultades para eliminar 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 (mira un ejemplo completo aquí).

Sin embargo, para el caso binomial, no existe una rutina independiente de fechas (no hay 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 "falsas" fechas, jugando con una función pseudo .yearFraction(FechaInicioFalsa, FechaFinFalsa); para encontrar dos fechas óptimas que coincidan con la fracción deseada. Luego utilizar esas dos fechas para calcular el precio. Sin embargo, esta estrategia parece ser 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, mira a continuación lo que he hecho hasta ahora, estoy atascado en la línea que instancia la 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

Tendrás que usar fechas falsas, como mencionaste.

Para hacer el proceso menos engorroso, puedes usar un contador de días con una fórmula sencilla 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 lo impone.

0 votos

Sí y no. Las fechas en realidad se ajustan a los nodos de la instancia pasada de TimeGrid 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 del ejercicio de la siguiente manera:

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

A continuación se muestra un ejemplo funcional 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