QL.require(a.exercise.type()==Exercise.Type.American , NOT_AN_AMERICAN_OPTION); // QA:[RG]::verified
QL.require(a.exercise instanceof AmericanExercise , NON_AMERICAN_EXERCISE_GIVEN); // QA:[RG]::verified
final AmericanExercise ex = (AmericanExercise)a.exercise;
QL.require(!ex.payoffAtExpiry() , PAYOFF_AT_EXPIRY_NOT_HANDLED); // QA:[RG]::verified
QL.require(a.payoff instanceof PlainVanillaPayoff , NON_PLAIN_PAYOFF_GIVEN); // QA:[RG]::verified
PlainVanillaPayoff payoff = (PlainVanillaPayoff)a.payoff;
final double /* @Real */variance = process.blackVolatility().currentLink().blackVariance(ex.lastDate(), payoff.strike());
double /* @DiscountFactor */dividendDiscount = process.dividendYield().currentLink().discount(ex.lastDate());
double /* @DiscountFactor */riskFreeDiscount = process.riskFreeRate().currentLink().discount(ex.lastDate());
double /* @Real */spot = process.stateVariable().currentLink().value();
QL.require(spot > 0.0, "negative or null underlying given"); // TODO: message
double /* @Real */strike = payoff.strike();
if (payoff.optionType()==Option.Type.Put) {
// use put-call symmetry
// swap spot and strike, has to be done inline
double tmp = spot; spot = strike; strike = tmp;
// swap riskFreeDiscount and dividenDiscount, has to be done inline
tmp = riskFreeDiscount; riskFreeDiscount = dividendDiscount; dividendDiscount = tmp;
payoff = new PlainVanillaPayoff(Option.Type.Call, strike);
}
if (dividendDiscount>=1.0) {
// early exercise is never optimal - use Black formula
final double /*@Real*/ forwardPrice = spot * dividendDiscount / riskFreeDiscount;