New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yahoo getOptionChain not longer working #92

Closed
user3477071 opened this Issue Jul 13, 2016 · 12 comments

Comments

Projects
None yet
8 participants
@user3477071

user3477071 commented Jul 13, 2016

I am using version 0.4-5 of quantmod and call to getOptionChain fails.

> getOptionChain("AMZN")
named list()

This used to work previously. Probably html format of yahoo has changed.

@joshuaulrich

This comment has been minimized.

Show comment
Hide comment
@joshuaulrich

joshuaulrich Jul 13, 2016

Owner

Thanks for the report. I confirm that the HTML has changed. It's not clear to me how to fix it at this point.

Owner

joshuaulrich commented Jul 13, 2016

Thanks for the report. I confirm that the HTML has changed. It's not clear to me how to fix it at this point.

@joshuaulrich joshuaulrich added the bug label Jul 13, 2016

@KenziTrader

This comment has been minimized.

Show comment
Hide comment
@KenziTrader

KenziTrader Jul 14, 2016

The following query returns a JSON object for the option chain:

https://query2.finance.yahoo.com/v7/finance/options/AAPL?&date=1471564800

KenziTrader commented Jul 14, 2016

The following query returns a JSON object for the option chain:

https://query2.finance.yahoo.com/v7/finance/options/AAPL?&date=1471564800

@vishalhawa

This comment has been minimized.

Show comment
Hide comment
@vishalhawa

vishalhawa Jul 21, 2016

Alternatively can the same be obtained from Google Finance?

vishalhawa commented Jul 21, 2016

Alternatively can the same be obtained from Google Finance?

@AndreMikulec

This comment has been minimized.

Show comment
Hide comment
@AndreMikulec

AndreMikulec Jul 31, 2016

What KenziTrader said.

IMHO: JSON strings, R lists and data.frames are easier to work with than XML anyways.

I do not know what 1463011200 means.
The situation seems like it is the number of seconds since the birth of UNIX.

> zoo::as.Date(1463011200/(3600*24))
[1] "2016-05-12"
> as.integer(zoo::as.Date("2016-05-12"))*(3600*24)
[1] 1463011200

Does anywone have a copy of what the output looked like before the change?

## Not run:

# Only the front-month expiry
AAPL.OPT <- getOptionChain("AAPL")
# All expiries
AAPL.OPTS <- getOptionChain("AAPL", NULL)
# All 2015 and 2016 expiries
AAPL.2015 <- getOptionChain("AAPL", "2015/2016")
## End(Not run)
> library(jsonlite)
> Res <- fromJSON('https://query2.finance.yahoo.com/v7/finance/options/AAPL?&date=1471564800')
> str(Res)
List of 1
 $ optionChain:List of 2
  ..$ result:'data.frame':      1 obs. of  6 variables:
  .. ..$ underlyingSymbol: chr "AAPL"
  .. ..$ expirationDates :List of 1
  .. .. ..$ : int [1:15] 1470355200 1470960000 1471564800 1472169600 1472774400 1473379200 1473984000 1477008000 1479427200 1484870400 ...
  .. ..$ strikes         :List of 1
  .. .. ..$ : num [1:75] 17.5 20 30 45 50 55 60 65 70 75 ...
  .. ..$ hasMiniOptions  : logi FALSE
  .. ..$ quote           :'data.frame': 1 obs. of  58 variables:
  .. .. ..$ quoteType                        : chr "EQUITY"
  .. .. ..$ quoteSourceName                  : chr "Delayed Quote"
  .. .. ..$ currency                         : chr "USD"
  .. .. ..$ sharesOutstanding                : num 5.48e+09
  .. .. ..$ fiftyDayAverageChangePercent     : num 0.0705
  .. .. ..$ twoHundredDayAverage             : num 99.4
  .. .. ..$ marketCap                        : num 5.71e+11
  .. .. ..$ bookValue                        : num 23.5
  .. .. ..$ fiftyDayAverage                  : num 97.3
  .. .. ..$ fiftyDayAverageChange            : num 6.86
  .. .. ..$ exchange                         : chr "NMS"
  .. .. ..$ postMarketChangePercent          : num 0.0384
  .. .. ..$ postMarketTime                   : int 1469836788
  .. .. ..$ postMarketPrice                  : num 104
  .. .. ..$ postMarketChange                 : num 0.04
  .. .. ..$ regularMarketChangePercent       : num -0.144
  .. .. ..$ regularMarketPreviousClose       : num 104
  .. .. ..$ bid                              : num 104
  .. .. ..$ ask                              : num 104
  .. .. ..$ bidSize                          : int 2
  .. .. ..$ askSize                          : int 1
  .. .. ..$ messageBoardId                   : chr "finmb_24937"
  .. .. ..$ fullExchangeName                 : chr "NasdaqGS"
  .. .. ..$ averageDailyVolume3Month         : int 37533150
  .. .. ..$ averageDailyVolume10Day          : int 42954475
  .. .. ..$ fiftyTwoWeekLowChange            : num 14.7
  .. .. ..$ fiftyTwoWeekLowChangePercent     : num 0.165
  .. .. ..$ fiftyTwoWeekHighChange           : num -19.6
  .. .. ..$ fiftyTwoWeekHighChangePercent    : num -0.159
  .. .. ..$ fiftyTwoWeekLow                  : num 89.5
  .. .. ..$ fiftyTwoWeekHigh                 : num 124
  .. .. ..$ dividendDate                     : int 1463011200
  .. .. ..$ earningsTimestamp                : int 1469577600
  .. .. ..$ earningsTimestampStart           : int 1477440000
  .. .. ..$ earningsTimestampEnd             : int 1477958400
  .. .. ..$ trailingAnnualDividendRate       : num 2.13
  .. .. ..$ trailingPE                       : num 12.1
  .. .. ..$ epsTrailingTwelveMonths          : num 8.58
  .. .. ..$ epsForward                       : num 8.9
  .. .. ..$ marketState                      : chr "CLOSED"
  .. .. ..$ shortName                        : chr "Apple Inc."
  .. .. ..$ regularMarketPrice               : num 104
  .. .. ..$ regularMarketTime                : int 1469822400
  .. .. ..$ regularMarketChange              : num -0.15
  .. .. ..$ regularMarketOpen                : num 104
  .. .. ..$ regularMarketDayHigh             : num 105
  .. .. ..$ regularMarketDayLow              : num 104
  .. .. ..$ regularMarketVolume              : int 24376597
  .. .. ..$ twoHundredDayAverageChange       : num 4.83
  .. .. ..$ twoHundredDayAverageChangePercent: num 0.0486
  .. .. ..$ forwardPE                        : num 11.7
  .. .. ..$ priceToBook                      : num 4.44
  .. .. ..$ sourceInterval                   : int 15
  .. .. ..$ exchangeTimezoneName             : chr "America/New_York"
  .. .. ..$ exchangeTimezoneShortName        : chr "EDT"
  .. .. ..$ gmtOffSetMilliseconds            : int -14400000
  .. .. ..$ longName                         : chr "Apple Inc."
  .. .. ..$ symbol                           : chr "AAPL"
  .. ..$ options         :List of 1
  .. .. ..$ :'data.frame':      1 obs. of  4 variables:
  .. .. .. ..$ expirationDate: int 1471564800
  .. .. .. ..$ hasMiniOptions: logi FALSE
  .. .. .. ..$ calls         :List of 1
  .. .. .. .. ..$ :'data.frame':        60 obs. of  15 variables:
  .. .. .. .. .. ..$ contractSymbol   : chr [1:60] "AAPL160819C00017500" "AAPL160819C00020000" "AAPL160819C00030000" "AAPL160819C00045000" ...
  .. .. .. .. .. ..$ strike           : num [1:60] 17.5 20 30 45 50 60 65 70 75 80 ...
  .. .. .. .. .. ..$ currency         : chr [1:60] "USD" "USD" "USD" "USD" ...
  .. .. .. .. .. ..$ lastPrice        : num [1:60] 77.6 79 64.2 49.2 53.8 ...
  .. .. .. .. .. ..$ change           : num [1:60] 0 0 0 0 0 ...
  .. .. .. .. .. ..$ percentChange    : num [1:60] 0 0 0 0 0 ...
  .. .. .. .. .. ..$ volume           : int [1:60] 1 50 0 0 1 11 1 5 7 38 ...
  .. .. .. .. .. ..$ openInterest     : int [1:60] 0 49 3 0 101 48 3 161 40 1347 ...
  .. .. .. .. .. ..$ bid              : num [1:60] 0 80 62.7 47.8 53.8 ...
  .. .. .. .. .. ..$ ask              : num [1:60] 0 80.6 63 48 54.9 ...
  .. .. .. .. .. ..$ contractSize     : chr [1:60] "REGULAR" "REGULAR" "REGULAR" "REGULAR" ...
  .. .. .. .. .. ..$ expiration       : int [1:60] 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 ...
  .. .. .. .. .. ..$ lastTradeDate    : int [1:60] 1467725517 1464187329 1462388531 1462388543 1469628862 1468596467 1468514015 1469800810 1469801256 1469817041 ...
  .. .. .. .. .. ..$ impliedVolatility: num [1:60] 0.00001 0.00001 0.00001 0.00001 1.45508 ...
  .. .. .. .. .. ..$ inTheMoney       : logi [1:60] TRUE TRUE TRUE TRUE TRUE TRUE ...
  .. .. .. ..$ puts          :List of 1
  .. .. .. .. ..$ :'data.frame':        66 obs. of  15 variables:
  .. .. .. .. .. ..$ contractSymbol   : chr [1:66] "AAPL160819P00045000" "AAPL160819P00050000" "AAPL160819P00055000" "AAPL160819P00060000" ...
  .. .. .. .. .. ..$ strike           : num [1:66] 45 50 55 60 65 70 75 80 81 82 ...
  .. .. .. .. .. ..$ currency         : chr [1:66] "USD" "USD" "USD" "USD" ...
  .. .. .. .. .. ..$ lastPrice        : num [1:66] 0.02 0.02 0.02 0.01 0.01 0.01 0.01 0.02 0.11 0.01 ...
  .. .. .. .. .. ..$ change           : num [1:66] 0 0 0.01 0 0 0 0 0.01 0 0 ...
  .. .. .. .. .. ..$ percentChange    : num [1:66] 0 0 100 0 0 0 0 100 0 0 ...
  .. .. .. .. .. ..$ volume           : int [1:66] 500 33 35 886 971 1 21 18 203 1 ...
  .. .. .. .. .. ..$ openInterest     : int [1:66] 1300 0 2621 2537 2669 2989 3688 6286 224 135 ...
  .. .. .. .. .. ..$ bid              : num [1:66] 0.01 0 0.01 0 0 0 0.01 0.01 0 0 ...
  .. .. .. .. .. ..$ ask              : num [1:66] 0.04 0 0.02 0.01 0.01 0.02 0.01 0.02 0.01 0.02 ...
  .. .. .. .. .. ..$ contractSize     : chr [1:66] "REGULAR" "REGULAR" "REGULAR" "REGULAR" ...
  .. .. .. .. .. ..$ expiration       : int [1:66] 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 ...
  .. .. .. .. .. ..$ lastTradeDate    : int [1:66] 1463512516 1467047812 1467381790 1468510759 1468510955 1469633394 1469805311 1469819117 1469563182 1469728448 ...
  .. .. .. .. .. ..$ impliedVolatility: num [1:66] 1.344 0.5 0.984 0.781 0.672 ...
  .. .. .. .. .. ..$ inTheMoney       : logi [1:66] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ error : NULL

AndreMikulec commented Jul 31, 2016

What KenziTrader said.

IMHO: JSON strings, R lists and data.frames are easier to work with than XML anyways.

I do not know what 1463011200 means.
The situation seems like it is the number of seconds since the birth of UNIX.

> zoo::as.Date(1463011200/(3600*24))
[1] "2016-05-12"
> as.integer(zoo::as.Date("2016-05-12"))*(3600*24)
[1] 1463011200

Does anywone have a copy of what the output looked like before the change?

## Not run:

# Only the front-month expiry
AAPL.OPT <- getOptionChain("AAPL")
# All expiries
AAPL.OPTS <- getOptionChain("AAPL", NULL)
# All 2015 and 2016 expiries
AAPL.2015 <- getOptionChain("AAPL", "2015/2016")
## End(Not run)
> library(jsonlite)
> Res <- fromJSON('https://query2.finance.yahoo.com/v7/finance/options/AAPL?&date=1471564800')
> str(Res)
List of 1
 $ optionChain:List of 2
  ..$ result:'data.frame':      1 obs. of  6 variables:
  .. ..$ underlyingSymbol: chr "AAPL"
  .. ..$ expirationDates :List of 1
  .. .. ..$ : int [1:15] 1470355200 1470960000 1471564800 1472169600 1472774400 1473379200 1473984000 1477008000 1479427200 1484870400 ...
  .. ..$ strikes         :List of 1
  .. .. ..$ : num [1:75] 17.5 20 30 45 50 55 60 65 70 75 ...
  .. ..$ hasMiniOptions  : logi FALSE
  .. ..$ quote           :'data.frame': 1 obs. of  58 variables:
  .. .. ..$ quoteType                        : chr "EQUITY"
  .. .. ..$ quoteSourceName                  : chr "Delayed Quote"
  .. .. ..$ currency                         : chr "USD"
  .. .. ..$ sharesOutstanding                : num 5.48e+09
  .. .. ..$ fiftyDayAverageChangePercent     : num 0.0705
  .. .. ..$ twoHundredDayAverage             : num 99.4
  .. .. ..$ marketCap                        : num 5.71e+11
  .. .. ..$ bookValue                        : num 23.5
  .. .. ..$ fiftyDayAverage                  : num 97.3
  .. .. ..$ fiftyDayAverageChange            : num 6.86
  .. .. ..$ exchange                         : chr "NMS"
  .. .. ..$ postMarketChangePercent          : num 0.0384
  .. .. ..$ postMarketTime                   : int 1469836788
  .. .. ..$ postMarketPrice                  : num 104
  .. .. ..$ postMarketChange                 : num 0.04
  .. .. ..$ regularMarketChangePercent       : num -0.144
  .. .. ..$ regularMarketPreviousClose       : num 104
  .. .. ..$ bid                              : num 104
  .. .. ..$ ask                              : num 104
  .. .. ..$ bidSize                          : int 2
  .. .. ..$ askSize                          : int 1
  .. .. ..$ messageBoardId                   : chr "finmb_24937"
  .. .. ..$ fullExchangeName                 : chr "NasdaqGS"
  .. .. ..$ averageDailyVolume3Month         : int 37533150
  .. .. ..$ averageDailyVolume10Day          : int 42954475
  .. .. ..$ fiftyTwoWeekLowChange            : num 14.7
  .. .. ..$ fiftyTwoWeekLowChangePercent     : num 0.165
  .. .. ..$ fiftyTwoWeekHighChange           : num -19.6
  .. .. ..$ fiftyTwoWeekHighChangePercent    : num -0.159
  .. .. ..$ fiftyTwoWeekLow                  : num 89.5
  .. .. ..$ fiftyTwoWeekHigh                 : num 124
  .. .. ..$ dividendDate                     : int 1463011200
  .. .. ..$ earningsTimestamp                : int 1469577600
  .. .. ..$ earningsTimestampStart           : int 1477440000
  .. .. ..$ earningsTimestampEnd             : int 1477958400
  .. .. ..$ trailingAnnualDividendRate       : num 2.13
  .. .. ..$ trailingPE                       : num 12.1
  .. .. ..$ epsTrailingTwelveMonths          : num 8.58
  .. .. ..$ epsForward                       : num 8.9
  .. .. ..$ marketState                      : chr "CLOSED"
  .. .. ..$ shortName                        : chr "Apple Inc."
  .. .. ..$ regularMarketPrice               : num 104
  .. .. ..$ regularMarketTime                : int 1469822400
  .. .. ..$ regularMarketChange              : num -0.15
  .. .. ..$ regularMarketOpen                : num 104
  .. .. ..$ regularMarketDayHigh             : num 105
  .. .. ..$ regularMarketDayLow              : num 104
  .. .. ..$ regularMarketVolume              : int 24376597
  .. .. ..$ twoHundredDayAverageChange       : num 4.83
  .. .. ..$ twoHundredDayAverageChangePercent: num 0.0486
  .. .. ..$ forwardPE                        : num 11.7
  .. .. ..$ priceToBook                      : num 4.44
  .. .. ..$ sourceInterval                   : int 15
  .. .. ..$ exchangeTimezoneName             : chr "America/New_York"
  .. .. ..$ exchangeTimezoneShortName        : chr "EDT"
  .. .. ..$ gmtOffSetMilliseconds            : int -14400000
  .. .. ..$ longName                         : chr "Apple Inc."
  .. .. ..$ symbol                           : chr "AAPL"
  .. ..$ options         :List of 1
  .. .. ..$ :'data.frame':      1 obs. of  4 variables:
  .. .. .. ..$ expirationDate: int 1471564800
  .. .. .. ..$ hasMiniOptions: logi FALSE
  .. .. .. ..$ calls         :List of 1
  .. .. .. .. ..$ :'data.frame':        60 obs. of  15 variables:
  .. .. .. .. .. ..$ contractSymbol   : chr [1:60] "AAPL160819C00017500" "AAPL160819C00020000" "AAPL160819C00030000" "AAPL160819C00045000" ...
  .. .. .. .. .. ..$ strike           : num [1:60] 17.5 20 30 45 50 60 65 70 75 80 ...
  .. .. .. .. .. ..$ currency         : chr [1:60] "USD" "USD" "USD" "USD" ...
  .. .. .. .. .. ..$ lastPrice        : num [1:60] 77.6 79 64.2 49.2 53.8 ...
  .. .. .. .. .. ..$ change           : num [1:60] 0 0 0 0 0 ...
  .. .. .. .. .. ..$ percentChange    : num [1:60] 0 0 0 0 0 ...
  .. .. .. .. .. ..$ volume           : int [1:60] 1 50 0 0 1 11 1 5 7 38 ...
  .. .. .. .. .. ..$ openInterest     : int [1:60] 0 49 3 0 101 48 3 161 40 1347 ...
  .. .. .. .. .. ..$ bid              : num [1:60] 0 80 62.7 47.8 53.8 ...
  .. .. .. .. .. ..$ ask              : num [1:60] 0 80.6 63 48 54.9 ...
  .. .. .. .. .. ..$ contractSize     : chr [1:60] "REGULAR" "REGULAR" "REGULAR" "REGULAR" ...
  .. .. .. .. .. ..$ expiration       : int [1:60] 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 ...
  .. .. .. .. .. ..$ lastTradeDate    : int [1:60] 1467725517 1464187329 1462388531 1462388543 1469628862 1468596467 1468514015 1469800810 1469801256 1469817041 ...
  .. .. .. .. .. ..$ impliedVolatility: num [1:60] 0.00001 0.00001 0.00001 0.00001 1.45508 ...
  .. .. .. .. .. ..$ inTheMoney       : logi [1:60] TRUE TRUE TRUE TRUE TRUE TRUE ...
  .. .. .. ..$ puts          :List of 1
  .. .. .. .. ..$ :'data.frame':        66 obs. of  15 variables:
  .. .. .. .. .. ..$ contractSymbol   : chr [1:66] "AAPL160819P00045000" "AAPL160819P00050000" "AAPL160819P00055000" "AAPL160819P00060000" ...
  .. .. .. .. .. ..$ strike           : num [1:66] 45 50 55 60 65 70 75 80 81 82 ...
  .. .. .. .. .. ..$ currency         : chr [1:66] "USD" "USD" "USD" "USD" ...
  .. .. .. .. .. ..$ lastPrice        : num [1:66] 0.02 0.02 0.02 0.01 0.01 0.01 0.01 0.02 0.11 0.01 ...
  .. .. .. .. .. ..$ change           : num [1:66] 0 0 0.01 0 0 0 0 0.01 0 0 ...
  .. .. .. .. .. ..$ percentChange    : num [1:66] 0 0 100 0 0 0 0 100 0 0 ...
  .. .. .. .. .. ..$ volume           : int [1:66] 500 33 35 886 971 1 21 18 203 1 ...
  .. .. .. .. .. ..$ openInterest     : int [1:66] 1300 0 2621 2537 2669 2989 3688 6286 224 135 ...
  .. .. .. .. .. ..$ bid              : num [1:66] 0.01 0 0.01 0 0 0 0.01 0.01 0 0 ...
  .. .. .. .. .. ..$ ask              : num [1:66] 0.04 0 0.02 0.01 0.01 0.02 0.01 0.02 0.01 0.02 ...
  .. .. .. .. .. ..$ contractSize     : chr [1:66] "REGULAR" "REGULAR" "REGULAR" "REGULAR" ...
  .. .. .. .. .. ..$ expiration       : int [1:66] 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 1471564800 ...
  .. .. .. .. .. ..$ lastTradeDate    : int [1:66] 1463512516 1467047812 1467381790 1468510759 1468510955 1469633394 1469805311 1469819117 1469563182 1469728448 ...
  .. .. .. .. .. ..$ impliedVolatility: num [1:66] 1.344 0.5 0.984 0.781 0.672 ...
  .. .. .. .. .. ..$ inTheMoney       : logi [1:66] FALSE FALSE FALSE FALSE FALSE FALSE ...
  ..$ error : NULL
@chandrab

This comment has been minimized.

Show comment
Hide comment
@chandrab

chandrab Jul 31, 2016

Expiration Date of 08/19/2016 = 1463011200 . I used this site to covert: http://www.unixtimestamp.com/index.php.
To convert:
as.numeric(as.POSIXct("2016-08-19",tz="UTC"))

chandrab commented Jul 31, 2016

Expiration Date of 08/19/2016 = 1463011200 . I used this site to covert: http://www.unixtimestamp.com/index.php.
To convert:
as.numeric(as.POSIXct("2016-08-19",tz="UTC"))

@AndreMikulec

This comment has been minimized.

Show comment
Hide comment
@AndreMikulec

AndreMikulec Jul 31, 2016

chandrab, I think you meant to say
= 1471564800
Yeah.

> as.numeric(as.POSIXct("2016-08-19",tz="UTC"))
[1] 1471564800
> as.integer(zoo::as.Date("2016-08-19"))*3600*24
[1] 1471564800

AndreMikulec commented Jul 31, 2016

chandrab, I think you meant to say
= 1471564800
Yeah.

> as.numeric(as.POSIXct("2016-08-19",tz="UTC"))
[1] 1471564800
> as.integer(zoo::as.Date("2016-08-19"))*3600*24
[1] 1471564800
@chandrab

This comment has been minimized.

Show comment
Hide comment
@chandrab

chandrab Aug 7, 2016

Before the change, the Yahoo Option Chains data columns were: Strike, Full_SymbolName_of_Option, Last, Change, Bid, Ask, Volume, Open Interest...this is for puts and calls

chandrab commented Aug 7, 2016

Before the change, the Yahoo Option Chains data columns were: Strike, Full_SymbolName_of_Option, Last, Change, Bid, Ask, Volume, Open Interest...this is for puts and calls

@milspec

This comment has been minimized.

Show comment
Hide comment
@milspec

milspec Aug 11, 2016

Hi All,
The following code fixed it for me. Unfortunately it adds a dependency on XML and RJson. Though I noticed the JSON data embedded in SCRIPT tags in the HTML, I didn't notice that there is a direct URL to get just the options JSON (nod to @KenziTrader). I modified my initial patch to grab just the option JSON.

source the following code after loading quantmod:

getOptionChain.yahoo.patch <- function(Symbols, Exp, ...)
{
  library("XML")
  library("rjson")

  dateToMillis <- function(x)
  {
    as.numeric(x) * 86400000    / 1000
  }

  parse.expiry <- function(x) {
    if (is.null(x))
      return(NULL)
    if (is.character(x))
    {
      x <- as.Date(x)
    }
    if (inherits(x, "Date") || inherits(x, "POSIXt"))
      return(dateToMillis(x))
    return(NULL)
  }

  getOptionChainFixed <- function(sym, Exp)
  {
    url <-
      paste("https://query2.finance.yahoo.com/v7/finance/options/",
            Symbols,
            sep = "")
    if (!missing(Exp)) {
      url <-
        paste(
          "https://query2.finance.yahoo.com/v7/finance/options/",
          Symbols,
          "?date=",
          parse.expiry(Exp),
          sep = ""
        )
    }

    opt <- readLines(url)
    opt <- paste(opt, collapse = '')
    json <- fromJSON(opt)
    calls <- json$optionChain$result[[1]]$options[[1]]$calls
    puts <- json$optionChain$result[[1]]$options[[1]]$puts
    price <- json$optionChain$result$quote$regularMarketPrice

    return (list(
      calls = chainToDf(calls),
      puts = chainToDf(puts),
      price = price,
      sym = sym
    ))
  }

  chainToDf <- function(theRawList)
  {
    theList <- list()
    for (i in 1:length(theRawList))
    {
      xx <-
        list(
          contractSymbol = theRawList[[i]]$contractSymbol,
          strike = theRawList[[i]]$strike,
          bid = theRawList[[i]]$bid,
          ask = theRawList[[i]]$ask,
          lastPrice = theRawList[[i]]$lastPrice,
          volume = theRawList[[i]]$volume,
          openInterest = theRawList[[i]]$openInterest
        )
      theList[[i]] <- xx
    }
    x <- do.call(rbind.data.frame, theList)
    rownames(x) <- x$contractSymbol
    y <-
      x[, c("strike",
            "bid",
            "ask",
            "lastPrice",
            "volume",
            "openInterest")]
    theNames <- c("Strike", "Bid", "Ask", "Last", "Vol", "OI")
    names(y) <- theNames
    for (i in theNames)
    {
      y[, i] <- as.numeric(as.character(y[, i]))
    }
    return(y)
  }

  getOptionChainFixed(Symbols, Exp)
}
assignInNamespace("getOptionChain.yahoo",
                  getOptionChain.yahoo.patch,
                  "quantmod")

milspec commented Aug 11, 2016

Hi All,
The following code fixed it for me. Unfortunately it adds a dependency on XML and RJson. Though I noticed the JSON data embedded in SCRIPT tags in the HTML, I didn't notice that there is a direct URL to get just the options JSON (nod to @KenziTrader). I modified my initial patch to grab just the option JSON.

source the following code after loading quantmod:

getOptionChain.yahoo.patch <- function(Symbols, Exp, ...)
{
  library("XML")
  library("rjson")

  dateToMillis <- function(x)
  {
    as.numeric(x) * 86400000    / 1000
  }

  parse.expiry <- function(x) {
    if (is.null(x))
      return(NULL)
    if (is.character(x))
    {
      x <- as.Date(x)
    }
    if (inherits(x, "Date") || inherits(x, "POSIXt"))
      return(dateToMillis(x))
    return(NULL)
  }

  getOptionChainFixed <- function(sym, Exp)
  {
    url <-
      paste("https://query2.finance.yahoo.com/v7/finance/options/",
            Symbols,
            sep = "")
    if (!missing(Exp)) {
      url <-
        paste(
          "https://query2.finance.yahoo.com/v7/finance/options/",
          Symbols,
          "?date=",
          parse.expiry(Exp),
          sep = ""
        )
    }

    opt <- readLines(url)
    opt <- paste(opt, collapse = '')
    json <- fromJSON(opt)
    calls <- json$optionChain$result[[1]]$options[[1]]$calls
    puts <- json$optionChain$result[[1]]$options[[1]]$puts
    price <- json$optionChain$result$quote$regularMarketPrice

    return (list(
      calls = chainToDf(calls),
      puts = chainToDf(puts),
      price = price,
      sym = sym
    ))
  }

  chainToDf <- function(theRawList)
  {
    theList <- list()
    for (i in 1:length(theRawList))
    {
      xx <-
        list(
          contractSymbol = theRawList[[i]]$contractSymbol,
          strike = theRawList[[i]]$strike,
          bid = theRawList[[i]]$bid,
          ask = theRawList[[i]]$ask,
          lastPrice = theRawList[[i]]$lastPrice,
          volume = theRawList[[i]]$volume,
          openInterest = theRawList[[i]]$openInterest
        )
      theList[[i]] <- xx
    }
    x <- do.call(rbind.data.frame, theList)
    rownames(x) <- x$contractSymbol
    y <-
      x[, c("strike",
            "bid",
            "ask",
            "lastPrice",
            "volume",
            "openInterest")]
    theNames <- c("Strike", "Bid", "Ask", "Last", "Vol", "OI")
    names(y) <- theNames
    for (i in theNames)
    {
      y[, i] <- as.numeric(as.character(y[, i]))
    }
    return(y)
  }

  getOptionChainFixed(Symbols, Exp)
}
assignInNamespace("getOptionChain.yahoo",
                  getOptionChain.yahoo.patch,
                  "quantmod")
@joshuaulrich

This comment has been minimized.

Show comment
Hide comment
@joshuaulrich

joshuaulrich Aug 24, 2016

Owner

@AndreMikulec the structure of the output for a single expiry before the change was:

R> str(quantmod::getOptionChain("AAPL"))
List of 2
 $ calls:'data.frame':  83 obs. of  7 variables:
  ..$ Strike: num [1:83] 10 15 17.5 20 22.5 25 30 40 45 50 ...
  ..$ Last  : num [1:83] 87.3 0 0 86.9 0 ...
  ..$ Chg   : num [1:83] -1.45 0 0 0 0 0 0 0 0 0 ...
  ..$ Bid   : num [1:83] 87.1 86 83.5 86.5 78.5 ...
  ..$ Ask   : num [1:83] 87.5 86.5 84 87 79 ...
  ..$ Vol   : int [1:83] 1 0 0 1 0 0 0 2 0 1 ...
  ..$ OI    : int [1:83] 21 0 0 0 0 0 0 0 0 1 ...
 $ puts :'data.frame':  91 obs. of  7 variables:
  ..$ Strike: num [1:91] 10 12.5 15 17.5 20 22.5 25 30 35 40 ...
  ..$ Last  : num [1:91] 0.01 0 0 0 0 0 0 0 0 0.02 ...
  ..$ Chg   : num [1:91] 0 0 0 0 0 0 0 0 0 0 ...
  ..$ Bid   : num [1:91] 0 0 0 0 0 0 0 0 0 0 ...
  ..$ Ask   : num [1:91] 0.01 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.04 0.02 ...
  ..$ Vol   : int [1:91] 100 0 0 0 0 0 0 0 0 0 ...
  ..$ OI    : int [1:91] 100 0 0 0 0 0 0 0 0 1 ...
R> head(quantmod::getOptionChain("AAPL")$calls)
                    Strike  Last   Chg   Bid   Ask Vol OI
AAPL160617C00010000   10.0 87.35 -1.45 87.10 87.55   1 21
AAPL160617C00015000   15.0  0.00  0.00 86.00 86.45   0  0
AAPL160617C00017500   17.5  0.00  0.00 83.50 83.95   0  0
AAPL160617C00020000   20.0 86.90  0.00 86.55 87.00   1  0
AAPL160617C00022500   22.5  0.00  0.00 78.55 78.95   0  0
AAPL160617C00025000   25.0  0.00  0.00 76.05 76.45   0  0
R> head(quantmod::getOptionChain("AAPL")$puts)
                    Strike Last Chg Bid  Ask Vol  OI
AAPL160617P00010000   10.0 0.01   0   0 0.01 100 100
AAPL160617P00012500   12.5 0.00   0   0 0.03   0   0
AAPL160617P00015000   15.0 0.00   0   0 0.03   0   0
AAPL160617P00017500   17.5 0.00   0   0 0.03   0   0
AAPL160617P00020000   20.0 0.00   0   0 0.03   0   0
AAPL160617P00022500   22.5 0.00   0   0 0.03   0   0

If all expiries were returned (Exp = NULL), then the result was a named list with an element for each expiry (name format was "%b.%d.%Y"). Each element contained the output from getOptionChain.yahoo.

Owner

joshuaulrich commented Aug 24, 2016

@AndreMikulec the structure of the output for a single expiry before the change was:

R> str(quantmod::getOptionChain("AAPL"))
List of 2
 $ calls:'data.frame':  83 obs. of  7 variables:
  ..$ Strike: num [1:83] 10 15 17.5 20 22.5 25 30 40 45 50 ...
  ..$ Last  : num [1:83] 87.3 0 0 86.9 0 ...
  ..$ Chg   : num [1:83] -1.45 0 0 0 0 0 0 0 0 0 ...
  ..$ Bid   : num [1:83] 87.1 86 83.5 86.5 78.5 ...
  ..$ Ask   : num [1:83] 87.5 86.5 84 87 79 ...
  ..$ Vol   : int [1:83] 1 0 0 1 0 0 0 2 0 1 ...
  ..$ OI    : int [1:83] 21 0 0 0 0 0 0 0 0 1 ...
 $ puts :'data.frame':  91 obs. of  7 variables:
  ..$ Strike: num [1:91] 10 12.5 15 17.5 20 22.5 25 30 35 40 ...
  ..$ Last  : num [1:91] 0.01 0 0 0 0 0 0 0 0 0.02 ...
  ..$ Chg   : num [1:91] 0 0 0 0 0 0 0 0 0 0 ...
  ..$ Bid   : num [1:91] 0 0 0 0 0 0 0 0 0 0 ...
  ..$ Ask   : num [1:91] 0.01 0.03 0.03 0.03 0.03 0.03 0.03 0.03 0.04 0.02 ...
  ..$ Vol   : int [1:91] 100 0 0 0 0 0 0 0 0 0 ...
  ..$ OI    : int [1:91] 100 0 0 0 0 0 0 0 0 1 ...
R> head(quantmod::getOptionChain("AAPL")$calls)
                    Strike  Last   Chg   Bid   Ask Vol OI
AAPL160617C00010000   10.0 87.35 -1.45 87.10 87.55   1 21
AAPL160617C00015000   15.0  0.00  0.00 86.00 86.45   0  0
AAPL160617C00017500   17.5  0.00  0.00 83.50 83.95   0  0
AAPL160617C00020000   20.0 86.90  0.00 86.55 87.00   1  0
AAPL160617C00022500   22.5  0.00  0.00 78.55 78.95   0  0
AAPL160617C00025000   25.0  0.00  0.00 76.05 76.45   0  0
R> head(quantmod::getOptionChain("AAPL")$puts)
                    Strike Last Chg Bid  Ask Vol  OI
AAPL160617P00010000   10.0 0.01   0   0 0.01 100 100
AAPL160617P00012500   12.5 0.00   0   0 0.03   0   0
AAPL160617P00015000   15.0 0.00   0   0 0.03   0   0
AAPL160617P00017500   17.5 0.00   0   0 0.03   0   0
AAPL160617P00020000   20.0 0.00   0   0 0.03   0   0
AAPL160617P00022500   22.5 0.00   0   0 0.03   0   0

If all expiries were returned (Exp = NULL), then the result was a named list with an element for each expiry (name format was "%b.%d.%Y"). Each element contained the output from getOptionChain.yahoo.

@saschakhakshouri

This comment has been minimized.

Show comment
Hide comment
@saschakhakshouri

saschakhakshouri Oct 4, 2018

@KenziTrader
I have a question. The query you provided:
https://query2.finance.yahoo.com/v7/finance/options/AAPL?&date=1471564800
does work, however it only returns options prices for the first expiry in the option chain.
It does return a list of available expiry dates, but not the option prices for each of these.
The date parameter you are passing does not refer to the option expiry. Do you know how to obtain option prices on the other expiry dates?

saschakhakshouri commented Oct 4, 2018

@KenziTrader
I have a question. The query you provided:
https://query2.finance.yahoo.com/v7/finance/options/AAPL?&date=1471564800
does work, however it only returns options prices for the first expiry in the option chain.
It does return a list of available expiry dates, but not the option prices for each of these.
The date parameter you are passing does not refer to the option expiry. Do you know how to obtain option prices on the other expiry dates?

@KenziTrader

This comment has been minimized.

Show comment
Hide comment
@KenziTrader

KenziTrader Oct 17, 2018

@saschakhakshouri, you should do a separate query for each expiration.

KenziTrader commented Oct 17, 2018

@saschakhakshouri, you should do a separate query for each expiration.

@saschakhakshouri

This comment has been minimized.

Show comment
Hide comment
@saschakhakshouri

saschakhakshouri Oct 17, 2018

Thanks- it worked perfectly

saschakhakshouri commented Oct 17, 2018

Thanks- it worked perfectly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment