8 votos

Los precios de una FixedRateBond en Quantlib: rendimiento vs TermStructure

Estoy tratando de precio de un simple tesoro de los estados UNIDOS en QuantLib, utilizando dos métodos. El primer método llama a FixedRatebond.dirtyPrice(...), pasando de un YTM y otros parámetros.

El segundo método implica la construcción de una FlatForward YieldTermStructure con el mismo YTM y parámetros como el método #1.

Los dos métodos me dan ligeramente diferente sucio de los precios, y espero que sean de la misma. ¿Alguien puede explicar lo que he hecho mal, o explicar por qué el sucio es el precio que debe ser diferente utilizando los dos métodos?

Aquí está el código de ejemplo (full disclosure: este código fue plagiado de aquí):

try {
    // date set up
    Calendar calendar = TARGET();

    Date settlementDate(28, January, 2011);
    // the settlement date must be a business day
    settlementDate = calendar.adjust(settlementDate);

    // Evaluation date
    Integer fixingDays = 1;
    Natural settlementDays = 1;
    Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days);
    Settings::instance().evaluationDate() = todaysDate;

    // bond set up  
    Real faceAmount = 100.0;
    Real redemption = 100.0;
    Date issueDate(27, January, 2011);
    Date maturity(31, August, 2020);
    Real couponRate = 0.03625;
    Real yield = 0.034921;

    RelinkableHandle<YieldTermStructure> discountingTermStructure;
    boost::shared_ptr<YieldTermStructure> flatTermStructure(
    new FlatForward(
        settlementDate,
        yield,
        ActualActual(ActualActual::Bond),
        Compounding::Compounded,
        Semiannual));
    discountingTermStructure.linkTo(flatTermStructure);

    // Pricing engine
    boost::shared_ptr<PricingEngine> bondEngine(
        new DiscountingBondEngine(discountingTermStructure));

     // Rate
    Schedule fixedBondSchedule(
        issueDate,
        maturity,
        Period(Semiannual),
        UnitedStates(UnitedStates::GovernmentBond),
        BusinessDayConvention::Unadjusted,
        BusinessDayConvention::Unadjusted,
        DateGeneration::Rule::Backward,
        false);

    FixedRateBond fixedRateBond(
        settlementDays,
        faceAmount,
        fixedBondSchedule,
        std::vector<Rate>(1, couponRate),
        ActualActual(ActualActual::Bond),
        BusinessDayConvention::Unadjusted,
        redemption,
        issueDate);

    //Calculate pricing without term structure
    Real cp = fixedRateBond.cleanPrice(yield, fixedRateBond.dayCounter(), Compounding::Compounded, Semiannual);
    Real dp = fixedRateBond.dirtyPrice(yield, fixedRateBond.dayCounter(), Compounding::Compounded, Semiannual);
    Rate ytm = fixedRateBond.yield(cp, fixedRateBond.dayCounter(), Compounding::Compounded, Semiannual);
    Real accrued = fixedRateBond.accruedAmount();

    fixedRateBond.setPricingEngine(bondEngine);


    // write column headings
    Size widths[] = { 18, 15, 15};

    std::cout << std::setw(widths[0]) <<  "                 "
        << std::setw(widths[1]) << "Without TS"
        << std::setw(widths[2]) << "With TS"
        << std::endl;

    Size width = widths[0]
                    + widths[1]
                            + widths[2];
    std::string rule(width, '-'), dblrule(width, '=');

    std::cout << rule << std::endl;

    std::cout << std::setw(widths[0]) << "Clean Price"
        << std::setw(widths[1]) << std::setprecision (8) << cp
        << std::setw(widths[2]) << std::setprecision (8) << fixedRateBond.cleanPrice()
        << std::endl;

    std::cout << std::setw(widths[0]) << "Dirty Price"
        << std::setw(widths[1]) << std::setprecision (8) << dp
        << std::setw(widths[2]) << std::setprecision (8) << fixedRateBond.dirtyPrice()
        << std::endl;

    std::cout << std::setw(widths[0]) << "Accrued"
        << std::setw(widths[1]) << std::setprecision (8) << accrued
        << std::setw(widths[2]) << std::setprecision (8) << fixedRateBond.accruedAmount()
        << std::endl;

    return 0;

} catch (std::exception& e) {
    std::cerr << e.what() << std::endl;
    return 1;
} catch (...) {
    std::cerr << "unknown error" << std::endl;
    return 1;
}

}

13voto

Brad Tutterow Puntos 5628

Día-el recuento de los convenios. No se puede vivir con ellos, usted no puede vivir sin ellos.

La razón de que los precios se diferencian es que el precio del motor no se puede calcular correctamente el tiempo durante el cual el primer cupón de descuento, y por lo tanto se vuelve ligeramente diferentes factores de descuento a aplicar a los valores de los cupones. Por favor, siéntese, se va a tomar algo de explicación.

En última instancia, ambos métodos de calcular el precio sucio por la adición de los valores de los cupones, cada uno con descuento de acuerdo a su fecha de pago. Donde difieren es en el cálculo de los factores de descuento.

El método que toma un rendimiento y los convenios correspondientes calcula descuentos, como es de esperar, por la capitalización de la producción. El descuento de $D_1$ para el primer cupón se obtiene acumulando el rendimiento con el resto de la vida del cupón; el descuento de $D_2$ para el segundo cupón, acumulando a lo largo de su vida y compuestos con el resultado anterior; y así sucesivamente hasta el último cupón. El problema es que, para calcular el devengo de tiempo correctamente de acuerdo con el pasado act/act(b) día cuente convención, también se necesita un período de referencia dado por la frecuencia de los cupones y en este caso es de 6 meses. Así, por ejemplo, la acumulación de tiempo para el primer cupón (desde el 28 de enero de 2011 al 28 de Febrero de 2011) debe ser calculado como:

dayCounter.yearFraction(Date(28,January,2011), Date(28,February,2011),
                        Date(28,August,2010),  Date(28,February,2011));

que devuelve 0.08423913043478261 (la tercera y cuarta fechas son las fechas de inicio y fin de los 6 meses del período de referencia). Si los cupones fueron anual, el resultado será un poco diferente: la referencia de la fecha de inicio anterior sería Feb.28 de 2010, volviendo 0.08493150684931507. La sobrecarga de la dirtyPrice método que toma un rendimiento usa cupón de información para seleccionar el período de referencia y calcula el primer factor de descuento de acuerdo con el primer valor anterior. El resultado es 0.997087920498809.

En su lugar, el método que se basa en los precios que utiliza el motor el rendimiento de la estructura a plazo t y sólo pide t.discount(coupon.date()) para cada uno de los cupones: el interfaz de la discount método no permite pasar alguna información extra sobre el período de referencia. Internamente, el mejor de la que la estructura a plazo puede hacer es calcular

dayCounter.yearFraction(Date(28,January,2011), Date(28,February,2011));

que, por defecto, se toma como el inicio y el final del período de referencia de la misma dos fechas que se pasan, lo anterior equivale a

dayCounter.yearFraction(Date(28,January,2011), Date(28,February,2011),
                        Date(28,January,2011), Date(28,February,2011));

esto devuelve 0.08333333333333333, y el correspondiente factor de descuento para el primer cupón es 0.9971191880350325.

Esta diferencia representa el cambio en los precios (los otros cupones no tienen ningún efecto: son todos regulares de 6 meses de cupón, y para ellos, el período de referencia es igual a la vida del cupón, haciendo de T igual a 0.5 en ambos casos). El precio devuelto por dirtyPrice() es 101.08980828425344; el devuelto por dirtyPrice(yield, ...) es 101.08663832294855; y si nos correcta de los diferentes factores de descuento anterior, obtenemos:

101.08980828425344 * 0.997087920498809 / 0.9971191880350325 = 101.08663832294862

que reconcilia a los precios.

Como una nota final: esto sólo ocurre con los días de conteo de los convenios que requieren de un período de referencia. Si usted pruebe su código con uno que no (es decir, act/360) los dos métodos dan el mismo precio.

Actualización (Septiembre De 2019):

Ahora es posible crear una instancia de la ActualActual día del contador que utiliza la correcta períodos de referencia para el cálculo. Crear instancias de ella como:

DayCounter dayCounter = ActualActual(ActualActual::Bond, fixedBondSchedule);

y el uso es para tanto del descuento y la curva de bonos. Cuando se le preguntó por año fracciones, va a recuperar el correcto periodo de referencia(s) de la programación y el uso de ellos. Esto le dará a los resultados correctos.

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