3
class ComputeIV
{
    public:    
        typedef std::pair<SimpleQuote,SimpleQuote> BidAsk;    

        static Volatility ComputeImpliedVol(const Date evalDate, const Date expiration, ptime quoteTime, const Option::Type optionType, 
                  const Real underlyingPrice, const Real optionPrice, const Real strike, const Rate riskFree) 
        {
            ActualActual actualActual;
            Settings::instance().evaluationDate() = evalDate;    

            Time timeToMaturity = actualActual.yearFraction(Settings::instance().evaluationDate(), expiration);

            time_duration timeOfDayDuration = quoteTime.time_of_day();
            timeToMaturity += (timeOfDayDuration.hours() + timeOfDayDuration.minutes()/60.0)/(24.0 * 365.0);               

            DiscountFactor discount = std::exp(-riskFree * timeToMaturity);

            Bisection bisection;
            Real accuracy = 0.000001, guess = .20;
            Real min = .05, max = .40;
            Volatility sigma = bisection.solve([&](const Volatility & sigma) {
                Real stdDev = sigma * std::sqrt(timeToMaturity);
                BlackCalculator blackCalculator(optionType, strike, underlyingPrice, stdDev, discount);
                    return blackCalculator.value() - optionPrice;
            }, accuracy, guess, min, max);  

            return sigma;    

        } 

    static const double& pTest(const std::string evalDateStr, const std::string expirationStr, const std::string quoteTimeStr, 
                               const int optType, const Real forwardBid, const Real forwardAsk, const Rate riskFree, const Real strike, 
                               const Real oBid, const Real oAsk)
    {
        std::cout << "Computing IV" << std::endl << std::flush;
        ActualActual actualActual;

        std::cout << evalDateStr << " " << expirationStr << " " << quoteTimeStr << std::endl << std::flush;
        std::cout << optType << " "  << riskFree << " " << forwardBid << " " << forwardAsk << " " << strike 
                  << " " <<  oBid << " " << oAsk << std::endl << std::flush;

        Date evalDate = DateParser::parseFormatted(evalDateStr.c_str(), "%d/%m/%Y");
        Settings::instance().evaluationDate() = evalDate;

        Date expiration = DateParser::parseFormatted(expirationStr.c_str(), "%d/%m/%Y");

        ptime quoteTime(from_iso_string(quoteTimeStr));
        time_duration timeOfDayDuration = quoteTime.time_of_day();

        Real price = (oBid + oAsk) / 2.0;    

        Option::Type oType = (optType > 0 ? Option::Call : Option::Put);
        Volatility *sigma = new Volatility();
        *sigma = ComputeIV::ComputeImpliedVol(evalDate, expiration, quoteTime, oType, 
                                forwardAsk, price, strike, riskFree);

        return *sigma;                        
    }

    private:        

};

When I call with these parameters,

from options import ComputeIV

PUT = -1
Call = 1

evalDate = "03/01/2017"
expiration = "07/07/2017";
quoteTime = "20170103T210000"
forwardBid = 84.19 
forwardAsk = 84.20  
riskFree = .015 
strike = 45.0
oBid = 0.10
oAsk = 0.17
oType = PUT

sigma = ComputeIV.pTest(evalDate, expiration, quoteTime, oType, forwardBid, forwardAsk, riskFree, strike, oBid, oAsk)

print "from python sigma = %f" % sigma

I get a runtime error:

Traceback (most recent call last):
  File "cboelivedata.py", line 575, in <module>
    main()
  File "cboelivedata.py", line 400, in main
    sigma = ComputeIV.pTest(evalDate, expiration, quoteTime, oType, forwardBid, forwardAsk, riskFree, strike, oBid, oAsk)
RuntimeError: root not bracketed: f[0.05,0.4] -> [-1.350000e-01,-2.434993e-02]
[idf@node3 python]$

Is there something I am not doing correctly here?

ABCD
  • 7,914
  • 9
  • 54
  • 90
Ivan
  • 7,448
  • 14
  • 69
  • 134

1 Answers1

4

You are using the Black Formula. In the Black-Scholes framework for European option, the option price is an increasing function of the volatility.

Your minimum and maximum range for your bisection volatility is 0.05 and 0.40. Are they good enough? Your put option is deep out-of-money, and thus needs a high volatility.

Let's check your range. Goto http://www.erieri.com/blackscholes, and type in the information like how I did:

enter image description here

The maximum put option price your solver can give you is about 0.0797, but your quote price is 0.135. Thus, there is no solution and your bisection root solver is correct to tell you that.

You will need to increase the volatility range. Try:

Real min = .05, max = 1.00;

You might not need 1.00 (this is too big), but you get the idea - you will need to adjust your root-solving range.

Try it and you will get your implied volatility.

ABCD
  • 7,914
  • 9
  • 54
  • 90
  • Thank you that works. Is there correct way to dynamically change the range based on bis/ask of the option, or is it best to just leave it one range for everything? – Ivan Jan 27 '17 at 16:53
  • @Ivan Leave it to a fixed range and adjust it if you have to. – ABCD Jan 27 '17 at 23:00