Skip to content
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

Add orats source for getOptionChain() #325

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions R/getOptionChain.R
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,107 @@ getOptionChain.yahoo <- function(Symbols, Exp, ...)
dftables
}

.make_orats_option_df <- function(option_df, call_cols, put_cols, extra_cols) {
call <- data.frame(
Ticker = option_df$ticker,
Strike = option_df$strike,
Bid = option_df$callBidPrice,
Ask = option_df$callAskPrice,
Vol = option_df$callVolume,
OI = option_df$callOpenInterest)
put <- data.frame(
Ticker = option_df$ticker,
Strike = option_df$strike,
Bid = option_df$putBidPrice,
Ask = option_df$putAskPrice,
Vol = option_df$putVolume,
OI = option_df$putOpenInterest)
call_extra <- option_df[, c("ticker", "strike", call_cols)]
colnames(call_extra) <- gsub("call|Call", "", colnames(call_extra))
put_extra <- option_df[, c("ticker", "strike", put_cols)]
colnames(put_extra) <- gsub("put|Put", "", colnames(put_extra))
extra <- option_df[, extra_cols]
return(list(call = call, put = put, call_extra = call_extra, put_extra = put_extra, extra = extra))
}


getOptionChain.orats <- function(Symbols, Exp, api.key, dte, delta) {
if(!requireNamespace("jsonlite", quietly=TRUE))
stop("package:",dQuote("jsonlite"),"cannot be loaded.")

if (missing(api.key)) {
# Check if they have ORATS_API_KEY defined
orats_key <- Sys.getenv("ORATS_API_KEY")
if (orats_key == "") {
stop(paste0("For the orats API an API key must be provided either",
" as a function argument or via an environment variable ORATS_API_KEY"))
} else {
api.key <- orats_key
}
}
# Construct URL
base_url <- "https://api.orats.io/datav2/strikes.json"
urlExp <- paste0(base_url, "?token=", api.key,
"&ticker=", paste0(Symbols, collapse=","))
if (!missing(dte)) {
if (length(dte) > 2) {
stop(paste0("Date to Expiry (dte) must be of size 2, but is size (", length(dte), ")"))
}
urlExp <- paste0(urlExp, "&dte=", paste0(dte, collapse = ","))
}
if (!missing(delta)) {
if (length(delta) > 2) {
stop(paste0("Date to Expiry (dte) must be of size 2, but is size (", length(delta), ")"))
}
urlExp <- paste0(urlExp, "&delta=", paste0(delta, collapse = ","))
}
# Fetch data (jsonlite::fromJSON will handle connection)
tbl <- jsonlite::fromJSON(urlExp)[["data"]]
tbl[, "expirDate"] <- as.POSIXct(tbl[, "expirDate"], format = "%Y-%m-%d")
tbl[, "tradeDate"] <- as.POSIXct(tbl[, "tradeDate"], format = "%Y-%m-%d")
tbl[, "updatedAt"] <- as.POSIXct(tbl[, "updatedAt"], format = "%Y-%m-%dT%H:%M:%SZ")
tbl[, "snapShotDate"] <- as.POSIXct(tbl[, "snapShotDate"], format = "%Y-%m-%dT%H:%M:%SZ")
tbl[, "quoteDate"] <- as.POSIXct(tbl[, "quoteDate"], format = "%Y-%m-%dT%H:%M:%SZ")
tbl_cols <- colnames(tbl)
call_cols <- tbl_cols[grep("call|Call", tolower(tbl_cols))]
put_cols <- tbl_cols[grep("put|Put", tolower(tbl_cols))]
extra_cols <- colnames(tbl)[!(colnames(tbl) %in% c(call_cols, put_cols))]
if(!missing(Exp)) {
if (is.null(Exp)) {
date_expr <- format(tbl[, "expirDate"], format = "%b.%d.%Y")
tbl2 <- split(tbl, factor(date_expr, levels = unique(date_expr)))
tbl3 <- lapply(tbl2, .make_orats_option_df, call_cols, put_cols, extra_cols)
return(tbl3)
} else {
all.expiries <- tbl$expirDate
all.expiries.posix <- .POSIXct(as.numeric(all.expiries), tz="UTC")
if(inherits(Exp, "Date")) {
valid.expiries <- as.Date(all.expiries.posix) %in% Exp
} else if(inherits(Exp, "POSIXt")) {
valid.expiries <- all.expiries.posix %in% Exp
} else if(is.character(Exp)) {
expiry.range <- range(unlist(lapply(Exp, .parseISO8601, tz="UTC")))
valid.expiries <- all.expiries.posix >= expiry.range[1] &
all.expiries.posix <= expiry.range[2]
}
if(all(!valid.expiries)) {
stop("Provided expiry date(s) [", paste0(Exp, collapse = ","), "] not found. Available dates are: ",
paste(as.Date(all.expiries.posix), collapse=", "))
}
exp_posixct <- as.POSIXct(Exp)
tbl_exp <- tbl[tbl$expirDate %in% exp_posixct,]
if (length(Exp) == 1) {
return(.make_orats_option_df(tbl_exp, call_cols, put_cols, extra_cols))
} else {
date_expr <- format(tbl_exp[, "expirDate"], format = "%b.%d.%Y")
tbl2 <- split(tbl_exp, factor(date_expr, levels = unique(date_expr)))
tbl3 <- lapply(tbl2, .make_orats_option_df, call_cols, put_cols, extra_cols)
return(tbl3)
}
}
} else {
tbl_exp <- tbl[tbl$expirDate == tbl$expirDate[1],]
return(.make_orats_option_df(tbl_exp, call_cols, put_cols, extra_cols))
}
}

23 changes: 19 additions & 4 deletions man/getOptionChain.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ Function to download option chain data from
data providers.
}
\usage{
getOptionChain(Symbols, Exp = NULL, src="yahoo", ...)
getOptionChain(Symbols, Exp = NULL, src="yahoo", \dots)
}
\arguments{
\item{Symbols}{ The name of the underlying symbol. }
\item{Symbols}{ The name of the underlying symbol. Source \sQuote{yahoo} only
allows for a single ticker while source \sQuote{orats} can return multiple tickers.}
\item{Exp}{ One or more expiration dates, NULL, or an ISO-8601 style string.
If \code{Exp} is missing, only the front month contract will be returned.
}
\item{src}{ Source of data. Currently only \sQuote{yahoo} is provided. }
\item{\dots}{ Additional parameters. }
\item{src}{ Source of data. One of \sQuote{yahoo} or \sQuote{orats} with
a default of \sQuote{yahoo}.}
\item{\dots}{ Additional parameters.}
}
\details{
This function is a wrapper to data-provider specific
Expand All @@ -32,8 +34,16 @@ If \code{Exp} is set to \code{NULL}, all expirations
will be returned. Not explicitly setting will only
return the front month.
}
<<<<<<< HEAD
\references{ \url{https://finance.yahoo.com} }
\author{ Jeffrey A. Ryan, Joshua M. Ulrich }
=======
\references{
\url{http://finance.yahoo.com},
\url{https://docs.orats.io/datav2-api-guide/data.html#strikes}
}
\author{ Jeffrey A. Ryan, Joshua M. Ulrich, Steve Bronder }
>>>>>>> Adds orats source for getOptionChain()
\examples{
\dontrun{
# Only the front-month expiry
Expand All @@ -42,6 +52,11 @@ AAPL.OPT <- getOptionChain("AAPL")
AAPL.OPTS <- getOptionChain("AAPL", NULL)
# All 2015 and 2016 expiries
AAPL.2015 <- getOptionChain("AAPL", "2015/2016")
# Using orats backend
NFLX.AAPL.2021 <- getOptionChain(c("NFLX", "AAPL"), "2021", src = "orats",
api.key = Sys.getenv("ORATS_API_KEY"))
}
}
\seealso{\code{\link{getOptionChain.orats}}}
\keyword{ utilities }% __ONLY ONE__ keyword per line

62 changes: 62 additions & 0 deletions man/getOptionChain.orats.Rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
\name{getOptionChain.orats}
\alias{getOptionChain.orats}
\title{ Download Option Chain Data from orats }
\description{
Function to download option chain data from orats.
}
\usage{
getOptionChain.orats(Symbols, Exp, api.key, dte, delta)
}
\arguments{
\item{Symbols}{ The name of the underlying symbol. Source \sQuote{yahoo} only
allows for a single ticker while source \sQuote{orats} can return multiple tickers.}
\item{Exp}{ One or more expiration dates, NULL, or an ISO-8601 style string.
If \code{Exp} is missing, only the front month contract will be returned.
}
\item{api.key}{ A character vector for the key given with an account for
accessing the orats API. If missing, the function will look for an
environment variable \code{ORATS_API_KEY} containing the API key.}
\item{dte}{ A vector of two integers giving
a range of expiry dates to subset the results by.}
\item{delta}{A vector of two integers giving
a range deltas to subset the results by.}
}
\details{
This function is a wrapper to data-provider specific
APIs. By default the data is sourced from yahoo.
}
\value{

For orats, returns A named list containing five data.frames, one
each for calls and puts that follows a similar form to the return
from yahoo, but does not have a Last price and instead has a
Ticker column for multiple ticker requests. The *_extra data.frames
contain additional information from the \sQuote{orats} API end point
whose definitions are available at the URL in the references.
If more than one expiration was requested, The results will be returned as
a list within list of length \code{length(Exp)}.
Each element of this list will be named with the expiration
month, day, and year (\%b.\%d.\%Y).

If \code{Exp} is set to \code{NULL}, all expirations
will be returned. Not explicitly setting will only
return the front month.
}
\references{
\url{https://docs.orats.io/datav2-api-guide/data.html#strikes}
}
\author{Steve Bronder }
\examples{
\dontrun{
# Only the front-month expiry
AAPL.OPT <- getOptionChain("AAPL",
api.key = Sys.getenv("ORATS_API_KEY"))
# All expiries
AAPL.OPTS <- getOptionChain("AAPL", NULL,
api.key = Sys.getenv("ORATS_API_KEY"))
# All 2015 and 2016 expiries
AAPL.2015 <- getOptionChain("AAPL", "2015/2016",
api.key = Sys.getenv("ORATS_API_KEY"))
}
}
\keyword{ utilities }% __ONLY ONE__ keyword per line