Closed user3477071 closed 8 years ago
Thanks for the report. I confirm that the HTML has changed. It's not clear to me how to fix it at this point.
The following query returns a JSON object for the option chain:
https://query2.finance.yahoo.com/v7/finance/options/AAPL?&date=1471564800
Alternatively can the same be obtained from Google Finance?
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
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, 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
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
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")
@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
.
@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, you should do a separate query for each expiration.
Thanks- it worked perfectly
I am using version 0.4-5 of quantmod and call to
getOptionChain
fails.This used to work previously. Probably html format of yahoo has changed.