diff --git a/account/plan-limits.md b/account/plan-limits.md index d54779c7..7ceb8c00 100644 --- a/account/plan-limits.md +++ b/account/plan-limits.md @@ -27,7 +27,7 @@ For users working with options, take care before repeatedly requesting quotes fo ::: :::note[Trial plans] -Starter Trial and Trader Trial do not support `mode=cached`. +Starter Trial, Trader Trial, and Prime Trial do not support `mode=cached`. ::: ## Device Restrictions diff --git a/api/options/quotes.mdx b/api/options/quotes.mdx index e0f6d335..f350a737 100644 --- a/api/options/quotes.mdx +++ b/api/options/quotes.mdx @@ -225,6 +225,30 @@ foreach (var quote in (await client.Options.GetQuoteAsync("AAPL271217C00250000") The option symbol according to OCC symbology. +- **underlying** `array[string]` + + The ticker symbol of the underlying security. + +- **expiration** `array[number]` + + The option's expiration date and time. Equity options expire at 4:00 PM Eastern and index options expire at 4:15 PM Eastern. All timestamps use US Eastern Time (America/New_York). See [Response Timezone](/docs/api/dates-and-times#response-timezone) for details. + +- **side** `array[string]` + + The response will be `call` or `put`. + +- **strike** `array[number]` + + The exercise price of the option. + +- **firstTraded** `array[date]` + + The date the option was first traded. + +- **dte** `array[number]` + + The number of days until the option expires. + - **ask** `array[number]` The ask price. diff --git a/api/rate-limiting.md b/api/rate-limiting.md index 0f1251b8..314717bb 100644 --- a/api/rate-limiting.md +++ b/api/rate-limiting.md @@ -82,5 +82,5 @@ We provide the following headers in our responses to help you manage the rate li - Paying customers can make use of the reduced-price cached mode. Use the `mode=cached` parameter on supported bulk endpoints to retrieve previously cached quotes instead of making a live request. This can save thousands of credits. For more details, refer to the [mode parameter documentation](/api/universal-parameters/mode). :::note[Trial plans] -`mode=cached` is not available on Starter Trial and Trader Trial plans. +`mode=cached` is not available on Starter Trial, Trader Trial, and Prime Trial plans. ::: diff --git a/internal/byok-audit-prompt.md b/internal/byok-audit-prompt.md index d30fe2e0..6ae6f22f 100644 --- a/internal/byok-audit-prompt.md +++ b/internal/byok-audit-prompt.md @@ -65,6 +65,12 @@ reading as a failure. ## The prompt +{/* TODO(compliance): confirm whether the 4:15:01 PM ET stock cutoff, taken from +account/data-freshness.md, is also the exchange redistribution-fee boundary for +stock data. The prompt's "One case that is neither a PASS nor a plain FAIL" +section treats it as historical, and so as fee-free, until compliance says +otherwise. See #222. */} + ```` You are an independent compliance auditor. Audit the repository at [REPO PATH] against the Market Data BYOK model and the Market Data data policies. Write your @@ -183,9 +189,9 @@ or UNRESOLVED. | ID | The rule | |----|----------| | E1 | Every request carries a unique `User-Agent` that names the application and its version. A library default such as `axios/1.6.0`, `python-requests/2.31.0`, or `okhttp/4.12.0` fails this rule. | -| E2 | Option chain requests use `mode=cached` unless the use case needs live data. A live chain costs one credit per contract; a cached chain costs one credit. | +| E2 | Option chain requests use `mode=cached` unless the use case needs live data. A live chain costs one credit per contract; a cached chain costs one credit. Cached mode is available only on paid plans that are not trials. Free Forever and every trial (Starter Trial, Trader Trial, Prime Trial) get a `402` for `mode=cached`, so on a `402` the application repeats the request without `mode`. | | E3 | Polling intervals fit a credit budget. A free key holds 100 credits a day. State the worst-case daily credit spend you can derive from the code. | -| E4 | The application handles `429`, `402`, and `403` with a message to the user. A `403` is the single-IP control and clears after five minutes with no requests. | +| E4 | The application handles `429`, `402`, and `403` with a message to the user. A `403` is the single-IP control. The block expires five minutes after the IP switch; further requests during the block do not extend it. | ### Group F — Onboarding and entitlement (all P2) @@ -193,7 +199,7 @@ or UNRESOLVED. |----|----------| | F1 | Onboarding tells the user they need a second account, and links to the Market Data sign-up page. | | F2 | Onboarding explains the verification step and the wait of up to one business day before real-time data arrives. | -| F3 | The application works on a delayed, historical, or quota-limited key, and reads response timestamps rather than assuming the data is live. A missing entitlement raises no error: the API returns the freshest data the user is entitled to. | +| F3 | The application works on a delayed, historical, or quota-limited key, and reads response timestamps rather than assuming the data is live. When the request sends no `mode`, a missing entitlement raises no error: the API returns the freshest data the user is entitled to. A paid plan is also downgraded silently. On a Free Forever or trial key, an explicit `mode=live`, `mode=delayed`, or `mode=eod` returns `402` "Feed not available for your plan.", and so does a date older than the plan allows. The application omits `mode` unless it needs one, and handles the `402`. | | F4 | The application does not assume every user is non-professional. A user our compliance team classifies as professional never receives real-time data on a self-service plan. | ## What is NOT a finding @@ -220,8 +226,8 @@ Do not report these. Each one is a legitimate design. A developer server that handles only **historical** data is not BYOK, and it is also not automatically a violation. The exchanges charge no redistribution fee -for historical data, meaning data from a completed session once the next session -has opened. Delayed data does not qualify. +for historical data, meaning data from a completed session. Delayed data does not +qualify. If you find a server path that carries only historical data, record it as a P1 against A2, and add a note that the product may qualify under the historical-only @@ -229,9 +235,14 @@ model. Recommend that the developer contact Market Data sales rather than recommending a code change. Say plainly that you cannot grant that model, and that only Market Data can. -Data becomes historical at the open of the next trading session. A product that -serves the previous session's data at 06:00 Eastern is serving delayed data and -is fee-liable until the bell. +Stocks and options become historical at different times: + +- Stock data becomes historical at 4:15:01 PM Eastern on the session day. +- Option data becomes historical at 9:30:01 AM Eastern, at the open of the next + trading session. + +A product that serves the previous session's option data at 06:00 Eastern is +serving delayed data and is fee-liable until the bell. ## Search seeds diff --git a/sheets/options/optionchain.md b/sheets/options/optionchain.md index ea003399..6d5327b4 100644 --- a/sheets/options/optionchain.md +++ b/sheets/options/optionchain.md @@ -1,12 +1,12 @@ --- title: OPTIONCHAIN -description: The OPTIONCHAIN formula fetches a current option chain into your spreadsheet. See the syntax, sample usage and data availability. +description: The OPTIONCHAIN formula fetches a current or end-of-day historical option chain into your spreadsheet. See the syntax, samples and data availability. sidebar_position: 3 sidebar_custom_props: badge: h --- -Fetches a current option chain from Market Data. +Fetches a current option chain, or the end-of-day option chain of a past trading day, from Market Data. ## Video Tutorial @@ -18,10 +18,16 @@ Fetches a current option chain from Market Data. =OPTIONCHAIN("AAPL","all,noheaders","60 DTE","150,160) =OPTIONCHAIN("AAPL","all","60 DTE","100-200","calls") ``` +### Historical Chains +```excel-formula +=OPTIONCHAIN("AAPL","strike,bid,ask","45 DTE","200-250","puts","2026-09-01") +=OPTIONCHAIN("AAPL",,,,,"last session") +=OPTIONCHAIN(A2,"strike,bid,ask","45 DTE","200-250","puts",B2) +``` ## Syntax ```excel-formula -=OPTIONCHAIN(underlying symbol, [attributes], expiration date, [strikes], [filters]) +=OPTIONCHAIN(underlying symbol, [attributes], expiration date, [strikes], [filters], [as of]) ``` - **underlying symbol** _(REQUIRED)_ Use the stock, etf, or underlying index symbol. @@ -32,6 +38,7 @@ Fetches a current option chain from Market Data. - "side" - Call or put. - "strike" - The option's strike price. - "first traded" - The date this option first began to trade. + - "dte" - Days to expiration: the calendar days until the option expires, counted from today on a current quote and from the quote date on a historical one. - "date", "updated" - The date and time of the quote. - "bid" – The bid price of the option. - "bid size" – The quantity of contracts offered at the bid price. @@ -55,7 +62,8 @@ Fetches a current option chain from Market Data. - **expiration date** - _(OPTIONAL)_ - The expiration date of the option chain. Options from this expiration will be returned. If no value is specified, the next monthly expiration will be used. - "date" - A single date in YYYY-MM-DD or MM/DD/YYYY format enclosed between quotes. - \[date cell reference] - A cell reference to a date in Sheets. - - "dte _number_" - Days to expiry. Return the expiration date most closely matching the indicated number. For example, if today was Jan 1 and you used a DTE of 45, the expiration closest to Feb 15 would be selected. + - "dte _number_" - Days to expiry. Return the expiration date most closely matching the indicated number. For example, if today was Jan 1 and you used a DTE of 45, the expiration closest to Feb 15 would be selected. With an **as of** date, the days are counted from that date instead of today. + - The expiration date is always the contract's expiration, never the quote date. To see a chain as it was on a past day, use **as of**. - **strikes** _(OPTIONAL)_ – Limit the strikes returned from the option chain formula to only the specified strikes or deltas. The formula will assume strikes for numbers greater than 1 and deltas for numbers less than 1 or when the word `delta` is placed before the number(s). - \[number] - A single number or a cell reference to a number. Example: `150` - \[decimal] - A decimal number will be interpreted as a delta value to be matched and the formula will return the strike that most closely matches the delta provided. Example: `.60` @@ -68,18 +76,26 @@ Fetches a current option chain from Market Data. - "string of decimals" - Seperate multiple deltas with commas. Example: `".50,.60.,70"` - "logical expression" - A logical expression. Example: `"<200 delta <.50"` - "limit \[number]" - Limit the output to \[number] strikes closest to the money. Example: `"limit 4"` + - Deltas are only available for current chains. Selecting strikes by delta together with an **as of** date returns an error; use strikes instead. - **filters** _(OPTIONAL)_ – Use specific keywords to further filter the option chain. - "call", "calls" - Only return calls. - "put", "puts" - Only return puts. - "itm", "in the money" - Only return in the money options. - "otm", "out of the money" - Only return out of the money options. - "nonstandard", "non-standard" - Include non-standard contracts in the optionchain output. +- **as of** _(OPTIONAL)_ – The quote date. Leave it out for the current chain, or give one past trading day to get that day's end-of-day chain. See [Working With Historical Chains](#working-with-historical-chains). + - _(omitted)_ or "current" - The current chain, the same as a formula without this parameter. + - "date" - A single date in YYYY-MM-DD or MM/DD/YYYY format enclosed between quotes. + - \[date cell reference] - A cell reference to a date in Sheets. + - "last session" - The most recent trading day whose end-of-day chain has been published. + - "yesterday", "today" - The calendar day before today, or today. On a weekend or holiday these return an error, so "last session" is usually the better choice. + - An empty cell or `""` returns an error, not the current chain. To switch a sheet between current and historical chains with one cell, write "current" in it. ## Usage Information ### Data Availability -The `OPTIONCHAIN` function fetches current option chain data. The type of data you receive depends on your user type and OPRA entitlement. This may include real-time data, 15-minute delayed data, or historical data, depending on the plan or access level. To get real-time options data, users need to sign the OPRA agreement. +Without an **as of** date, the `OPTIONCHAIN` function fetches current option chain data. The type of data you receive depends on your user type and OPRA entitlement. This may include real-time data, 15-minute delayed data, or historical data, depending on the plan or access level. To get real-time options data, users need to sign the OPRA agreement. | User Type | OPRA Entitlement | Data Type | |------------------|------------------|------------------------| @@ -89,6 +105,17 @@ The `OPTIONCHAIN` function fetches current option chain data. The type of data y | Professional | ❌ | Historical (1 day old) | | Unknown | Any | Historical (1 day old) | +### Working With Historical Chains + +With an **as of** date, `OPTIONCHAIN` returns the chain as it closed on that trading day. + +- Only end-of-day chains are available. There are no intraday snapshots, and only one date per formula. +- The columns are the same as for a current chain. Implied volatility and the greeks (delta, gamma, theta, vega) are blank, and selecting strikes by delta is not available. +- Open interest is the figure settled out of the previous session, as described under the "open interest" attribute. +- A date in the future, a weekend or a market holiday returns an error. Today's chain returns a "not available yet" error until the end-of-day chain is published after the close. +- A relative date such as "last session" is resolved when the formula calculates. It updates when the sheet is refreshed or a referenced cell changes, not on its own as days pass. +- Historical data is subject to your plan's limits. [Learn more about plan limits](/account/plan-limits). + :::info[What are entitlements?] Entitlements are permissions granted by exchanges that allow access to their data. To get real-time options data, users need to sign the [OPRA agreement](/account/entitlements). [Learn more about entitlements](/account/entitlements). ::: diff --git a/sheets/options/optiondata.md b/sheets/options/optiondata.md index a174edde..335e9afd 100644 --- a/sheets/options/optiondata.md +++ b/sheets/options/optiondata.md @@ -1,10 +1,10 @@ --- title: OPTIONDATA -description: The OPTIONDATA formula fetches a current or historical option quote into your spreadsheet. See the syntax, sample usage and data availability. +description: The OPTIONDATA formula fetches current or historical option quotes for one contract or a whole range of contracts. See the syntax, samples and limits. sidebar_position: 1 --- -Fetches a current or historical option quote from Market Data. +Fetches current or historical option quotes from Market Data, for one option contract or many at once. ## Sample Usage ```excel-formula @@ -13,14 +13,28 @@ Fetches a current or historical option quote from Market Data. =OPTIONDATA("AAPL271217C00250000", "date,bid,ask", "9/1/2022", "1/31/2023") =OPTIONDATA("AAPL271217C00250000", "all", TODAY()-30, 30) ``` +### Multiple Contracts +```excel-formula +=OPTIONDATA(A1:A500) +=OPTIONDATA(A1:A500, "bid,ask,noheaders") +=OPTIONDATA("AAPL271217C00250000,AAPL271217P00250000", "mid") +=OPTIONDATA(A1:A500, "mid", "9/15/2026") +=OPTIONDATA(A1:D50, "symbol,mid") +``` ## Syntax ```excel-formula =OPTIONDATA(option symbol, [attributes], start date, end date) ``` -- **option symbol** _(REQUIRED)_ Use the current OCC option symbol format for the option symbol, even for historic options prior to the symbol format change in 2010. +- **option symbol** _(REQUIRED)_ Use the current OCC option symbol format for the option symbol, even for historic options prior to the symbol format change in 2010. Several contracts can be fetched at once: pass a range of cells in a single row or a single column, several OCC symbols separated by commas, or a table of four columns with one contract per row. See [Working With Multiple Contracts](#working-with-multiple-contracts). - **attribute** _(OPTIONAL "price" by default)_ Use at least one of the following attributes; seperate multiple attributes with commas: - "symbol" - The OCC option symbol. + - "underlying" - The underlying symbol. + - "expiration" - The option's expiration date. + - "side" - Call or put. + - "strike" - The option's strike price. + - "first traded" - The date this option first began to trade. + - "dte" - Days to expiration: the calendar days until the option expires, counted from today on a current quote and from the quote date on a historical one. - "date", "updated" - The date and time of the quote. - "price", "mid", "mark" – The midpoint price of the option. - "bid" – The bid price of the option. @@ -41,7 +55,7 @@ Fetches a current or historical option quote from Market Data. - "vega" - The vega of the option. - "all" – Returns all values. - "noheaders" – Returns values without column headers. -- **start date** _(OPTIONAL)_ – The start date when fetching historical data. If start date is specified, but endDate is not, only the single day's data is returned. +- **start date** _(OPTIONAL)_ – The start date when fetching historical data. If start date is specified, but endDate is not, only the single day's data is returned. When fetching more than one contract, only a single date may be used. - **end date** _(OPTIONAL)_ – The end date when fetching historical data, or the number of calendar days (not trading days) from startDate for which to return data. ## Usage Information @@ -80,8 +94,36 @@ When you use `OPTIONDATA` with date parameters, it returns historical option quo If you attempt to access historical data older than your plan's limit permits, the formula will return an error. [Learn more about plan limits](/account/plan-limits). ::: +### Working With Multiple Contracts + +A single `OPTIONDATA` formula can fetch quotes for many option contracts at once. Pass a range of cells, several OCC symbols separated by commas, or a table of contracts as the option symbol. + +- One row comes back for each contract, in the same order as your cells, even when the range is a row. Wrap the formula in `TRANSPOSE()` to lay the results out horizontally. +- A contract that cannot be served (not found, expired, or misspelled) keeps its place, so the results stay aligned with your contracts. Its row shows what you entered in the symbol column, with the other columns blank, so you can spot it. Request the `symbol` attribute to see it; without it the row is blank. +- Use a single historical date (start date only). Date ranges are not supported with more than one contract. +- A range must be a single row, a single column, or a table of exactly four columns. Any other table, such as three or five columns, returns an error. +- A row of four cells can describe one contract in parts: underlying, expiration date, strike and side (for example, `AAPL | 12/17/2027 | 250 | call`). On its own, a row like that is read as a single contract, so it also accepts a date range. +- With more than one contract the results include a header row. Add `noheaders` to the attributes to line the results up with your cells. +- For best results use OCC symbols, or a table with dates in `YYYY-MM-DD` format and numeric strikes. Contracts written in words are slower to read, and a long list of them may fill in over a few refreshes. + +#### Tables of Contracts + +A table of four columns is read as one contract per row, with the underlying, expiration date, strike and side in its columns: + +| | A | B | C | D | +|---|------|------------|-----|------| +| 1 | AAPL | 2027-12-17 | 250 | call | +| 2 | AAPL | 2027-12-17 | 250 | put | +| 3 | MSFT | 2027-12-17 | 500 | call | + +`=OPTIONDATA(A1:D3, "symbol,mid")` returns a header row and one row for each of the three contracts. + +- The columns can be in any order. The first row sets it, and every other row is read the same way. +- Because of that, the first row must be a contract, not a header. A table that starts with a header row returns an error, so start the range on the first contract (for example, `A2:D50`). +- A later row that does not fit the order of the first row (columns swapped, a missing or misspelled cell) fails on its own, without affecting the other rows. + ## Notes - All parameters must be enclosed in quotation marks or be references to cells containing text. A possible exception is when end date is specified as a number of days. -- Results will be returned as a value within a single cell if a single attribute is requested. Multiple attributes or multi-day results will be returned with column headers. +- Results will be returned as a value within a single cell if a single attribute is requested for a single contract. Multiple attributes, multiple contracts or multi-day results will be returned with column headers. - Dates and times are returned in the same timezone of the exchange. \ No newline at end of file diff --git a/sheets/stocks/stockdata.md b/sheets/stocks/stockdata.md index 976fac10..0d33fa32 100644 --- a/sheets/stocks/stockdata.md +++ b/sheets/stocks/stockdata.md @@ -60,8 +60,11 @@ Fetches a current stock quote or historical stock candles from Market Data. It c - "bidSize" – The quantity of shares offered at the bid price. - "askSize" – The quantity of shares offered at the ask price. - "volume" – The quantity of shares traded. + - "52weekHigh" – The 52-week high for the stock. + - "52weekLow" – The 52-week low for the stock. + - "52week" – Adds both 52-week columns. "all" does not include them: use "all,52week" to return every value and the 52-week high and low. - "symbol" - The ticker symbol of the stock. _Only returned when using a bulk quotes formula._ - - "all" – Returns all values. + - "all" – Returns all values except the 52-week high and low. - **start date** _(OPTIONAL)_ The start date when fetching historical data. If start date is specified, but endDate is not, only the single day’s data is returned. Multiple tickers may be used if only a single day's data is being returned. diff --git a/sheets/universal-attributes/no-headers.md b/sheets/universal-attributes/no-headers.md index 0497e225..78723499 100644 --- a/sheets/universal-attributes/no-headers.md +++ b/sheets/universal-attributes/no-headers.md @@ -1,6 +1,6 @@ --- title: No Headers -description: Add the noheaders attribute to any Market Data Google Sheets formula, such as STOCKQUOTE or OPTIONDATA, to leave the header row out of the output. +description: Add the noheaders attribute to any Market Data Google Sheets formula, such as STOCKDATA or OPTIONDATA, to leave the header row out of the output. sidebar_position: 1 --- @@ -8,8 +8,9 @@ Add the "noheaders" attribute to exclude the header row from the output of any M ## Sample Usage ```excel-formula -=STOCKQUOTE("AAPL","all,noheaders") =STOCKDATA("AAPL", "all,noheaders") +=STOCKDATA(A1:A50, "mid,noheaders") +=OPTIONDATA(A1:A50, "bid,ask,noheaders") =OPTIONDATA("AAPL271217C00250000", "bid,ask,noheaders", "1/5/2026", "2/5/2026") ``` @@ -24,6 +25,6 @@ Add `noheaders` anywhere in the attribute list of any Market Data formula. Ensur :::info -The `noheaders` attribute is only needed if you've requested more than one attribute. If you request a single attribute in any Market Data formula, the output will be a single cell with no headers. +The `noheaders` attribute is needed whenever the output has more than one row or column: several attributes, several symbols or contracts, or a date range. A single attribute for a single symbol and date returns one cell with no header. :::