Documentation
¶
Overview ¶
Package options provides access to the Market Data options endpoints: option chains (Chain), expiration dates (Expirations), single and bulk contract quotes (Quote and Quotes), and OCC option symbol lookup (Lookup). It is used through the Options service on a marketdata client rather than on its own.
API documentation: https://www.marketdata.app/docs/api/options/index
Zero Values and Null Data ¶
Numeric fields use Go value types (float64, int64) rather than pointers. When the API returns null for a field, it is unmarshaled as the zero value (0 for integers, 0.0 for floats). This means a zero value may represent either an actual zero or the absence of data. For fields like IV and the Greeks (Delta, Gamma, Theta, Vega), a zero value may indicate that the data was not calculable rather than a true zero. Timestamp fields are the exception: a null or absent timestamp decodes to the zero time.Time, so IsZero reliably detects missing data.
Index ¶
- type CSVService
- func (s *CSVService) Chain(ctx context.Context, symbol string, opts ...ChainOption) (*response.CSVResponse, error)
- func (s *CSVService) Expirations(ctx context.Context, symbol string, opts ...ExpirationOption) (*response.CSVResponse, error)
- func (s *CSVService) Quote(ctx context.Context, optionSymbol string, opts ...QuoteOption) (*response.CSVResponse, error)
- func (s *CSVService) Quotes(ctx context.Context, optionSymbols []string, opts ...QuoteOption) (map[string]*response.CSVResponse, error)
- type ChainOption
- func WithAM(am bool) ChainOption
- func WithChainDate(t time.Time) ChainOption
- func WithExpirationTypes(f ExpirationTypeFilter) ChainOption
- func WithExpiry(f ExpiryFilter) ChainOption
- func WithMaxAsk(max float64) ChainOption
- func WithMaxBid(max float64) ChainOption
- func WithMaxBidAskSpread(max float64) ChainOption
- func WithMaxBidAskSpreadPct(max float64) ChainOption
- func WithMinAsk(min float64) ChainOption
- func WithMinBid(min float64) ChainOption
- func WithMinOpenInterest(min int) ChainOption
- func WithMinVolume(min int) ChainOption
- func WithNonstandard(nonstandard bool) ChainOption
- func WithPM(pm bool) ChainOption
- func WithRange(r Moneyness) ChainOption
- func WithSide(side OptionSide) ChainOption
- func WithStrike(f StrikeFilter) ChainOption
- func WithStrikeLimit(limit int) ChainOption
- type ExpirationOption
- type ExpirationType
- type ExpirationTypeFilter
- type Expirations
- type ExpiryFilter
- type Moneyness
- type OptionQuote
- type OptionQuoteWindow
- type OptionSide
- type OptionType
- type OptionsChain
- type QuoteOption
- type Service
- func (s *Service) AsCSV() *CSVService
- func (s *Service) Chain(ctx context.Context, symbol string, opts ...ChainOption) (*OptionsChain, *response.Response, error)
- func (s *Service) Expirations(ctx context.Context, symbol string, opts ...ExpirationOption) (*Expirations, *response.Response, error)
- func (s *Service) GetChain(symbol string, opts ...ChainOption) (*OptionsChain, error)
- func (s *Service) GetExpirations(symbol string, opts ...ExpirationOption) (*Expirations, error)
- func (s *Service) GetLookup(underlying string, expiration time.Time, strike float64, optionType OptionType) (string, error)
- func (s *Service) GetLookupQuery(query string) (string, error)
- func (s *Service) GetQuote(optionSymbol string, opts ...QuoteOption) (*OptionQuote, error)
- func (s *Service) GetQuoteHistory(optionSymbol string, opts ...QuoteOption) ([]OptionQuote, error)
- func (s *Service) GetQuotes(optionSymbols []string, opts ...QuoteOption) ([]OptionQuote, error)
- func (s *Service) GetQuotesBySymbol(optionSymbols []string, opts ...QuoteOption) (map[string]*OptionQuote, error)
- func (s *Service) Lookup(ctx context.Context, underlying string, expiration time.Time, strike float64, ...) (string, *response.Response, error)
- func (s *Service) LookupQuery(ctx context.Context, query string) (string, *response.Response, error)
- func (s *Service) Quote(ctx context.Context, optionSymbol string, opts ...QuoteOption) (*OptionQuote, *response.Response, error)
- func (s *Service) QuoteHistory(ctx context.Context, optionSymbol string, opts ...QuoteOption) ([]OptionQuote, *response.Response, error)
- func (s *Service) Quotes(ctx context.Context, optionSymbols []string, opts ...QuoteOption) ([]OptionQuote, *response.Response, error)
- func (s *Service) QuotesBySymbol(ctx context.Context, optionSymbols []string, opts ...QuoteOption) (map[string]*OptionQuote, *response.Response, error)
- type StrikeFilter
- func ByDelta(d float64) StrikeFilter
- func ByDeltas(deltas ...float64) StrikeFilter
- func MaxStrike(x float64) StrikeFilter
- func MinStrike(x float64) StrikeFilter
- func Strike(x float64) StrikeFilter
- func StrikeExpr(expr string) StrikeFilter
- func StrikeRange(lo, hi float64) StrikeFilter
- func Strikes(strikes ...float64) StrikeFilter
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CSVService ¶
type CSVService struct {
// contains filtered or unexported fields
}
CSVService is the CSV facet of options, reached through Service.AsCSV. Every endpoint here returns a response.CSVResponse carrying the API's raw CSV text — see ADR-018 for why this exists alongside the typed JSON methods on Service. The SDK does not parse the CSV into rows; callers get the text exactly as the API sent it.
Service.Lookup has no CSV facet: it resolves to a single OCC symbol string, not tabular data.
func (*CSVService) Chain ¶
func (s *CSVService) Chain(ctx context.Context, symbol string, opts ...ChainOption) (*response.CSVResponse, error)
Chain fetches the options chain for an underlying stock symbol as CSV. See Service.Chain for parameter and validation details.
func (*CSVService) Expirations ¶
func (s *CSVService) Expirations(ctx context.Context, symbol string, opts ...ExpirationOption) (*response.CSVResponse, error)
Expirations fetches the expiration dates for an underlying stock symbol as CSV. See Service.Expirations for parameter and validation details.
func (*CSVService) Quote ¶
func (s *CSVService) Quote(ctx context.Context, optionSymbol string, opts ...QuoteOption) (*response.CSVResponse, error)
Quote fetches a single option contract's quote as CSV. See Service.Quote for parameter and validation details.
func (*CSVService) Quotes ¶
func (s *CSVService) Quotes(ctx context.Context, optionSymbols []string, opts ...QuoteOption) (map[string]*response.CSVResponse, error)
Quotes fetches quotes for multiple option contracts as CSV, one request per symbol (mirroring Service.Quotes' own per-symbol fan-out), and returns a map keyed by option symbol instead of merging into one result — each contract's CSV text is independent, unlike candle chunks of the same time series. The first error cancels the remaining in-flight requests (ADR-014).
The options apply to every symbol in the batch, so a historical window is expressible for a watchlist and not only for a single contract — the same reason Service.Quotes takes a slice plus options rather than a variadic symbol list.
Unlike Service.Quotes, there is no NoData omission: every requested symbol gets an entry in the map holding whatever the API returned for it (see ADR-018 — the CSV/HTML facets have no NoData concept).
type ChainOption ¶
type ChainOption interface {
// contains filtered or unexported methods
}
ChainOption is a functional option that filters or otherwise refines a Service.Chain request. Chain options combine: pass several to narrow the chain by expiration, strike, side, liquidity, and more. The two mutually-exclusive parameter groups are each collapsed into a single sealed-union option — WithStrike and WithExpiry — so the API's silently-conflicting combinations cannot be written.
func WithAM ¶
func WithAM(am bool) ChainOption
WithAM controls whether AM-settled contracts are included. Pass true to limit the chain to AM-settled contracts or false to exclude them; when the option is not used, settlement is not filtered. Settlement style is meaningful only for index options (for example SPX, NDX); on single-stock and ETF options the API tolerates the parameter but it has no effect.
func WithChainDate ¶
func WithChainDate(t time.Time) ChainOption
WithChainDate requests the option chain as it stood on a single historical trading day (date=YYYY-MM-DD). Only the calendar date is used; a zero time returns the current chain. It is independent of the expiration selectors, so a historical chain can still be narrowed by expiration or strike. (A from/to date range filters expirations, not history — use options.ExpirationBetween via WithExpiry for that.)
func WithExpirationTypes ¶
func WithExpirationTypes(f ExpirationTypeFilter) ChainOption
WithExpirationTypes filters the chain by expiration cadence, either including or excluding a set of types via a single ExpirationTypeFilter value. Because inclusion and exclusion are one value, the API's forbidden include/exclude mix cannot be expressed.
func WithExpiry ¶
func WithExpiry(f ExpiryFilter) ChainOption
WithExpiry sets the chain's expiration selector from a single ExpiryFilter value, such as options.OnExpiration(t), options.InDTE(45), or options.InMonthOfYear(6, 2026). It replaces the API's mutually-exclusive expiration, dte, month, and year parameters with one option.
func WithMaxAsk ¶
func WithMaxAsk(max float64) ChainOption
WithMaxAsk limits the chain to contracts whose ask price is less than or equal to max.
func WithMaxBid ¶
func WithMaxBid(max float64) ChainOption
WithMaxBid limits the chain to contracts whose bid price is less than or equal to max.
func WithMaxBidAskSpread ¶
func WithMaxBidAskSpread(max float64) ChainOption
WithMaxBidAskSpread limits the chain to contracts whose bid-ask spread is less than or equal to max, expressed in dollars. See WithMaxBidAskSpreadPct for a relative version.
func WithMaxBidAskSpreadPct ¶
func WithMaxBidAskSpreadPct(max float64) ChainOption
WithMaxBidAskSpreadPct limits the chain to contracts whose bid-ask spread is less than or equal to max as a percentage of the UNDERLYING price — not of the contract's own midpoint, which this godoc claimed until 2026-08-20. The distinction matters: on a $316 underlying, 0.15 admits a $0.47 spread, while a caller reading "percentage of the midpoint" would expect it to admit only spreads under 15% of a mid that is often well under a dollar.
Verified live by sweeping the value against one chain: 0.09 admitted only contracts whose spread was at most 9% of the underlying, 0.11 at most 11%, 0.13 at most 13% — tracking the underlying exactly at every step, and never the midpoint. See WithMaxBidAskSpread for an absolute dollar version, which is unambiguous.
func WithMinAsk ¶
func WithMinAsk(min float64) ChainOption
WithMinAsk limits the chain to contracts whose ask price is greater than or equal to min.
func WithMinBid ¶
func WithMinBid(min float64) ChainOption
WithMinBid limits the chain to contracts whose bid price is greater than or equal to min. Useful for excluding illiquid or worthless contracts.
func WithMinOpenInterest ¶
func WithMinOpenInterest(min int) ChainOption
WithMinOpenInterest limits the chain to contracts with open interest greater than or equal to min, filtering out thinly held contracts.
func WithMinVolume ¶
func WithMinVolume(min int) ChainOption
WithMinVolume limits the chain to contracts with trading volume greater than or equal to min, filtering out thinly traded contracts.
func WithNonstandard ¶
func WithNonstandard(nonstandard bool) ChainOption
WithNonstandard controls whether nonstandard contracts (for example, adjusted contracts created by splits or mergers) are included in the chain. Pass true to include them or false to exclude them; when the option is not used, the API default applies.
func WithPM ¶
func WithPM(pm bool) ChainOption
WithPM controls whether PM-settled contracts are included. Pass true to limit the chain to PM-settled contracts or false to exclude them; when the option is not used, settlement is not filtered. Settlement style is meaningful only for index options (for example SPX, NDX); on single-stock and ETF options the API tolerates the parameter but it has no effect.
func WithRange ¶
func WithRange(r Moneyness) ChainOption
WithRange filters the chain by moneyness, using one of MoneynessITM, MoneynessOTM, or MoneynessAll. MoneynessUnset leaves the filter off. Pair it with WithStrikeLimit to ask for "the N strikes around the money".
func WithSide ¶
func WithSide(side OptionSide) ChainOption
WithSide limits the chain to one side of the market: SideCall for calls only or SidePut for puts only. Passing SideBoth leaves the parameter unset, which returns both sides (the default).
func WithStrike ¶
func WithStrike(f StrikeFilter) ChainOption
WithStrike sets the chain's contract selector from a single StrikeFilter value, such as options.Strike(150), options.StrikeRange(150, 160), or options.ByDelta(0.30). It replaces the API's mutually-exclusive strike and delta parameters with one option, so they can never conflict.
func WithStrikeLimit ¶
func WithStrikeLimit(limit int) ChainOption
WithStrikeLimit limits the chain to the n strikes nearest the money on EACH side of it, so a request can come back with up to 2n distinct strikes, not n (verified live 2026-08-20: strikeLimit=1 returned 2 distinct strikes, 2 returned 4, 3 returned 6). Values less than or equal to zero leave the limit unset.
type ExpirationOption ¶
type ExpirationOption interface {
// contains filtered or unexported methods
}
ExpirationOption is a functional option that refines a Service.Expirations request. The two filters are independent and may be combined.
func WithExpirationDate ¶
func WithExpirationDate(d time.Time) ExpirationOption
WithExpirationDate requests the expiration dates that were available on the given historical date rather than today's list. Only the calendar date is used; a zero time leaves the parameter unset.
func WithExpirationStrike ¶
func WithExpirationStrike(strike float64) ExpirationOption
WithExpirationStrike limits the expiration list to dates that have a contract listed at the given strike price. The value must be greater than zero to take effect.
type ExpirationType ¶
type ExpirationType string
ExpirationType identifies an expiration cadence for the chain's expiration-type filter (WithExpirationTypes).
const ( // Weekly is a weekly expiration cadence. Weekly ExpirationType = "weekly" // Monthly is a standard monthly expiration cadence. Monthly ExpirationType = "monthly" // Quarterly is a quarterly expiration cadence. Quarterly ExpirationType = "quarterly" )
type ExpirationTypeFilter ¶
type ExpirationTypeFilter interface {
// contains filtered or unexported methods
}
ExpirationTypeFilter includes or excludes expiration cadences (weekly, monthly, quarterly) from the chain. It is a sealed union built with exactly one of IncludeExpirationTypes or ExcludeExpirationTypes. The API forbids mixing inclusion and exclusion of expiration types in one request ("weekly=true&monthly=false" is an error); because the choice of include vs. exclude is a single value here, that illegal mix cannot be written.
func ExcludeExpirationTypes ¶
func ExcludeExpirationTypes(types ...ExpirationType) ExpirationTypeFilter
ExcludeExpirationTypes excludes the given expiration cadences from the chain (for example ExcludeExpirationTypes(options.Quarterly) sends quarterly=false). Passing none is a no-op.
func IncludeExpirationTypes ¶
func IncludeExpirationTypes(types ...ExpirationType) ExpirationTypeFilter
IncludeExpirationTypes limits the chain to only the given expiration cadences (for example IncludeExpirationTypes(options.Weekly, options.Monthly) sends weekly=true&monthly=true). Passing none is a no-op.
type Expirations ¶
type Expirations struct {
// Dates is the list of expiration dates, in Eastern time.
Dates []time.Time
// Updated is when the server last refreshed this expirations list, as
// reported by the API's response-level updated field. It is the zero
// time if the API omits the field.
Updated time.Time
}
Expirations is the result of a Service.Expirations request: the expiration dates with listed option contracts for an underlying symbol, plus the server's response-level update time. Both mirror the API response exactly.
func (Expirations) String ¶
func (e Expirations) String() string
String returns a summary of the expirations list.
type ExpiryFilter ¶
type ExpiryFilter interface {
// contains filtered or unexported methods
}
ExpiryFilter selects which expirations a Service.Chain request returns. It is a sealed union: build it with exactly one of the mode constructors below and pass it to WithExpiry. Because an ExpiryFilter is a single value, the API's mutually-exclusive expiry selectors can never be combined by mistake — combining expiration with dte makes the API silently honor expiration, and combining expiration with month/year yields an empty (broken) response.
The constructors mirror the ways the API accepts an expiry filter:
AllExpirations() // every listed expiration -> expiration=all OnExpiration(t) // a single expiration date -> expiration=YYYY-MM-DD InDTE(days) // the expiry nearest days out -> dte=days InMonth(month) // every year's given month -> month=month InYear(year) // every month of a given year -> year=year InMonthOfYear(m, y) // one specific month and year -> month=m&year=y
month must be 1 through 12, year a four-digit year (at least 1900), and dte zero or greater. Values are checked before any request is made.
Note that omitting the filter entirely is NOT the same as AllExpirations: with no expiry filter the chain endpoint returns only the front-month expiration.
func AllExpirations ¶
func AllExpirations() ExpiryFilter
AllExpirations requests the whole chain across every listed expiration (expiration=all).
This is not the same as omitting the expiry filter: with no expiry filter the chain endpoint returns only the front-month (nearest) expiration, so AllExpirations is the only way to obtain the complete chain. For a liquid underlying the difference is large — an AAPL chain returns roughly 190 contracts across 1 expiration unfiltered, against roughly 3,500 contracts across 24 expirations with AllExpirations — so the request is correspondingly more expensive in API credits. The independent filters (side, strike, the liquidity filters, the expiration-type filters) still narrow the result on top of it.
func ExpirationBetween ¶
func ExpirationBetween(from, to time.Time) ExpiryFilter
ExpirationBetween limits the chain to contracts expiring within an explicit, inclusive date range (from=YYYY-MM-DD&to=YYYY-MM-DD). Only the calendar dates are used. It selects which expirations are returned and so is mutually exclusive with the other expiry selectors (the API forbids combining a from/to expiration range with dte).
func InDTE ¶
func InDTE(days int) ExpiryFilter
InDTE limits the chain to the expiration closest to the given number of days to expiry, counted from today (dte=days).
func InMonth ¶
func InMonth(month int) ExpiryFilter
InMonth limits the chain to contracts expiring in the given calendar month across all years (month=month), expressed as 1 through 12.
func InMonthOfYear ¶
func InMonthOfYear(month, year int) ExpiryFilter
InMonthOfYear limits the chain to contracts expiring in a specific month of a specific year (month=month&year=year).
func InYear ¶
func InYear(year int) ExpiryFilter
InYear limits the chain to contracts expiring in the given four-digit year across all months (year=year).
func OnExpiration ¶
func OnExpiration(t time.Time) ExpiryFilter
OnExpiration limits the chain to contracts expiring on the given date (expiration=YYYY-MM-DD). Only the calendar date is used.
type Moneyness ¶
type Moneyness string
Moneyness is the chain's moneyness filter, passed to WithRange. It is a closed set of API keywords rather than a free string, so a typo cannot reach the wire as a silently-ignored filter.
const ( // MoneynessITM limits the chain to in-the-money contracts. MoneynessITM Moneyness = "itm" // MoneynessOTM limits the chain to out-of-the-money contracts. MoneynessOTM Moneyness = "otm" // MoneynessAll requests every contract regardless of moneyness (the // API default). MoneynessAll Moneyness = "all" // MoneynessUnset leaves the filter off, equivalent to omitting the option. MoneynessUnset Moneyness = "" )
type OptionQuote ¶
type OptionQuote struct {
// OptionSymbol is the OCC option symbol
OptionSymbol string `json:"optionSymbol"`
// Underlying is the underlying stock symbol
Underlying string `json:"underlying"`
// Expiration is the expiration date
Expiration time.Time `json:"expiration"`
// Strike is the strike price
Strike float64 `json:"strike"`
// Type is call or put
Type OptionType `json:"side"`
// Bid is the bid price
Bid float64 `json:"bid"`
// BidSize is the bid size
BidSize int `json:"bidSize"`
// Ask is the ask price
Ask float64 `json:"ask"`
// AskSize is the ask size
AskSize int `json:"askSize"`
// Last is the last trade price
Last float64 `json:"last"`
// Volume is the trading volume
Volume int64 `json:"volume"`
// OpenInterest is the open interest
OpenInterest int64 `json:"openInterest"`
// IV is the implied volatility
IV float64 `json:"iv"`
// Delta is the delta greek
Delta float64 `json:"delta"`
// Gamma is the gamma greek
Gamma float64 `json:"gamma"`
// Theta is the theta greek
Theta float64 `json:"theta"`
// Vega is the vega greek
Vega float64 `json:"vega"`
// Rho is the rho greek — the contract's sensitivity to interest rates.
// The API models rho internally but does not currently serialize it on
// the chain or quotes endpoints (verified live 2026-08-12), so this
// field is zero today. It is declared so that the value surfaces without
// an SDK change once the API emits it, matching sdk-java, which models it
// for the same reason.
Rho float64 `json:"rho"`
// Mid is the midpoint price from the API
Mid float64 `json:"mid"`
// UnderlyingPrice is the current price of the underlying
UnderlyingPrice float64 `json:"underlyingPrice"`
// IntrinsicValue is the intrinsic value of the option
IntrinsicValue float64 `json:"intrinsicValue"`
// ExtrinsicValue is the extrinsic (time) value of the option
ExtrinsicValue float64 `json:"extrinsicValue"`
// FirstTraded is the date the option was first traded
FirstTraded time.Time `json:"firstTraded"`
// DTE is the days to expiration
DTE int `json:"dte"`
// InTheMoney indicates if the option is ITM
InTheMoney bool `json:"inTheMoney"`
// Updated is when this contract was last updated
Updated time.Time `json:"updated"`
}
OptionQuote is a quote for a single option contract, including pricing, volume, open interest, implied volatility, and the Greeks. It is used both for the entries of an OptionsChain returned by Service.Chain and for the single-contract responses of Service.Quote and Service.Quotes. Timestamps are normalized to Eastern time (the exchange time zone). See the package documentation for how null API values map to Go zero values.
func (*OptionQuote) CalcMid ¶
func (c *OptionQuote) CalcMid() float64
CalcMid calculates the bid-ask midpoint locally from the Bid and Ask fields, unlike the Mid field, which is the midpoint reported by the API.
func (*OptionQuote) Spread ¶
func (c *OptionQuote) Spread() float64
Spread returns the bid-ask spread (Ask minus Bid).
func (OptionQuote) String ¶
func (c OptionQuote) String() string
String returns a summary of the option contract.
type OptionQuoteWindow ¶
type OptionQuoteWindow interface {
// contains filtered or unexported methods
}
OptionQuoteWindow selects the date range for a Service.Quote request. It is a sealed union: build it with exactly one of the mode constructors below and pass it to WithOptionQuoteWindow. Because an OptionQuoteWindow is a single value, the API's mutually-exclusive date parameters can never be combined by mistake — sending both date and from/to returns HTTP 400 ("Invalid date. Use either date, or from and to.").
The constructors mirror the ways the API accepts a quote window:
QuoteOnDate(t) // a single historical date -> date=YYYY-MM-DD QuoteRange(from, to) // an explicit date range -> from=...&to=... QuoteLastN(n) // the n most recent quotes -> countback=n QuoteLastNUntil(n, to) // n quotes ending at to -> countback=n&to=...
Only the calendar date of each time.Time is used. A countback must be greater than zero. The countback modes mirror the stocks and funds date windows: the API pairs countback with to, never with from, and that pairing is the only one expressible here.
func QuoteLastN ¶
func QuoteLastN(n int) OptionQuoteWindow
QuoteLastN requests n quotes for the contract (countback=n), sent with an explicit to= anchor of today's date in Eastern time. n must be greater than zero.
The anchor is required: this endpoint ignores a countback that arrives without a to=, returning a single current quote instead of n.
Known API defect ¶
The endpoint currently returns the n OLDEST quotes of the contract's history rather than the n most recent, and ignores the to= anchor when choosing them (verified live 2026-08-11: countback=3 with to= of 2026-08-11, 2026-08-08, and 2025-08-13 all return the same three earliest rows). Until that is fixed, prefer QuoteRange when you need a specific period. The SDK sends the parameters exactly as documented and does not attempt to compensate; integration/discrepancy_test.go carries the strict assertion that will pass once the API is corrected.
func QuoteLastNUntil ¶
func QuoteLastNUntil(n int, to time.Time) OptionQuoteWindow
QuoteLastNUntil requests n quotes ending on the given date (countback=n&to=YYYY-MM-DD). n must be greater than zero and to must not be zero. Only the calendar date of to is used.
See QuoteLastN for the known API defect that currently makes this endpoint ignore the to= anchor and return the contract's oldest quotes.
func QuoteOnDate ¶
func QuoteOnDate(t time.Time) OptionQuoteWindow
QuoteOnDate requests the contract's quote on a single historical date (date=YYYY-MM-DD).
func QuoteRange ¶
func QuoteRange(from, to time.Time) OptionQuoteWindow
QuoteRange requests the contract's quotes across an explicit date range (from=...&to=...).
type OptionSide ¶
type OptionSide string
OptionSide is the side filter for options chain requests, passed to WithSide. Use SideCall for calls only, SidePut for puts only, or SideBoth (the default) for both sides of the chain.
const ( // SideCall limits a chain request to call options. SideCall OptionSide = "call" // SidePut limits a chain request to put options. SidePut OptionSide = "put" // SideBoth requests both calls and puts (the default). SideBoth OptionSide = "" )
type OptionType ¶
type OptionType string
OptionType identifies a contract as a call or a put. It is used as the Type field of OptionQuote and as the required contract type argument to Service.Lookup. Use the Call and Put constants.
const ( // Call is a call option contract. Call OptionType = "call" // Put is a put option contract. Put OptionType = "put" )
type OptionsChain ¶
type OptionsChain struct {
// Underlying is the underlying stock symbol
Underlying string
// Options is the list of option quotes in the chain
Options []OptionQuote
}
OptionsChain is the result of a Service.Chain request: the set of option contracts listed for a single underlying symbol, after any server-side filters have been applied. Each contract appears as an OptionQuote in the Options slice, carrying its own quote-snapshot Updated time; the API reports no chain-level timestamp, so none is exposed here.
func (OptionsChain) String ¶
func (oc OptionsChain) String() string
String returns a summary of the options chain.
type QuoteOption ¶
type QuoteOption interface {
// contains filtered or unexported methods
}
QuoteOption is a functional option that refines a Service.Quote request. The historical date range is set with WithOptionQuoteWindow using a single OptionQuoteWindow value, so the API's mutually-exclusive date and from/to parameters cannot be combined.
func WithOptionQuoteWindow ¶
func WithOptionQuoteWindow(w OptionQuoteWindow) QuoteOption
WithOptionQuoteWindow requests a historical quote for a single contract from a single OptionQuoteWindow value: options.QuoteOnDate(t) for a single day or options.QuoteRange(from, to) for a range. Omitting it returns the current quote.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service provides access to the Market Data options endpoints. It is not meant to be constructed directly; use the Options field of the marketdata client, which shares the client's HTTP transport, rate-limit tracking, and concurrency pool.
func NewService ¶
NewService creates a new options service backed by the given HTTP client. Most callers should use the Options service on a marketdata client rather than calling NewService directly.
func (*Service) AsCSV ¶
func (s *Service) AsCSV() *CSVService
AsCSV returns the CSV facet of this service.
Example ¶
package main
import (
"context"
"fmt"
"log"
"github.com/MarketDataApp/sdk-go/v2/marketdata"
)
func main() {
client, err := marketdata.NewClient()
if err != nil {
log.Fatal(err)
}
defer func() { _ = client.Close() }()
csv, err := client.Options.AsCSV().Chain(context.Background(), "AAPL")
if err != nil {
log.Fatal(err)
}
fmt.Print(csv.CSV())
}
Output:
func (*Service) Chain ¶
func (s *Service) Chain(ctx context.Context, symbol string, opts ...ChainOption) (*OptionsChain, *response.Response, error)
Chain fetches the options chain for an underlying stock symbol, returning a real-time or historical OptionsChain with one OptionQuote per contract. The symbol is required; all other parameters are optional and supplied as ChainOption values.
Without an expiry filter the API returns only the front-month (nearest) expiration, not the whole chain. To fetch every listed expiration, pass options.AllExpirations() to WithExpiry — and expect a much larger response, billed accordingly.
The two groups of mutually-exclusive API parameters are each expressed as a single sealed-union option, so the API's silently-conflicting combinations cannot be written: WithStrike selects contracts by strike or delta, and WithExpiry selects expirations by date, dte, month, year, or an expiration range. WithChainDate requests a historical snapshot as of a day and is independent. Free filters such as WithSide, WithStrikeLimit, WithRange, the bid/ask and liquidity filters, and the expiration-type filters combine freely. See the ChainOption constructors in this package for the complete set.
Option values that cannot be encoded in the type system (a strike or delta out of range, a month outside 1..12, a malformed date range) are rejected with a sdkerrors.ValidationError before any request is made.
A symbol the API does not recognize is reported as a [NotFoundError]. A valid request that simply matches no contracts is not an error: Chain returns an empty chain (safe to range), a nil error, and a response whose NoData field is true. See the "Missing Data and Unknown Symbols" section of the marketdata package documentation.
API documentation: https://www.marketdata.app/docs/api/options/chain
Example:
chain, _, err := client.Options.Chain(ctx, "AAPL",
options.WithExpiry(options.OnExpiration(time.Now().AddDate(0, 1, 0))),
options.WithStrike(options.StrikeRange(150, 160)),
)
Example ¶
ExampleService_Chain fetches a filtered options chain for AAPL, limiting the result to a single expiration and a strike range.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/MarketDataApp/sdk-go/v2/marketdata"
"github.com/MarketDataApp/sdk-go/v2/marketdata/options"
)
func main() {
client, err := marketdata.NewClient() // token from MARKETDATA_TOKEN
if err != nil {
log.Fatal(err)
}
defer func() { _ = client.Close() }()
expiration := time.Now().AddDate(0, 1, 0)
chain, _, err := client.Options.Chain(context.Background(), "AAPL",
options.WithExpiry(options.OnExpiration(expiration)),
options.WithStrike(options.StrikeRange(150, 200)),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(chain)
}
Output:
func (*Service) Expirations ¶
func (s *Service) Expirations(ctx context.Context, symbol string, opts ...ExpirationOption) (*Expirations, *response.Response, error)
Expirations fetches the expiration dates with listed option contracts for an underlying stock symbol. The returned Expirations carries the dates in Eastern time plus the server's response-level update time, mirroring the API response. The symbol is required. The optional ExpirationOption values WithExpirationStrike (limit to expirations offering a given strike) and WithExpirationDate (list the expirations that were available on a past date) refine the request.
A request with no listed expirations is not an error: Expirations returns an empty result (Dates is safe to range), a nil error, and a response whose NoData field is true. Note that options/expirations answers an unknown symbol with an unmarked 404 too, so an unrecognized symbol is reported the same way rather than as a [NotFoundError] — the API sends nothing that tells the two apart.
API documentation: https://www.marketdata.app/docs/api/options/expirations
Example:
exps, _, err := client.Options.Expirations(ctx, "AAPL")
if err != nil {
log.Fatal(err)
}
if exps != nil {
for _, d := range exps.Dates { ... }
}
Example ¶
ExampleService_Expirations lists the available expiration dates for AAPL.
package main
import (
"context"
"fmt"
"log"
"github.com/MarketDataApp/sdk-go/v2/marketdata"
)
func main() {
client, err := marketdata.NewClient()
if err != nil {
log.Fatal(err)
}
defer func() { _ = client.Close() }()
expirations, _, err := client.Options.Expirations(context.Background(), "AAPL")
if err != nil {
log.Fatal(err)
}
if expirations != nil {
for _, exp := range expirations.Dates {
fmt.Println(exp.Format("2006-01-02"))
}
}
}
Output:
func (*Service) GetChain ¶
func (s *Service) GetChain(symbol string, opts ...ChainOption) (*OptionsChain, error)
GetChain is a convenience wrapper for Service.Chain that uses context.Background() and discards the response metadata. It accepts the same required symbol and optional ChainOption filters, and shares Chain's no-data behavior: when the API returns 404, GetChain returns a nil chain and a nil error.
Example ¶
ExampleService_GetChain uses the convenience wrapper, which needs no context and returns only the chain and an error.
package main
import (
"fmt"
"log"
"time"
"github.com/MarketDataApp/sdk-go/v2/marketdata"
"github.com/MarketDataApp/sdk-go/v2/marketdata/options"
)
func main() {
client, err := marketdata.NewClient()
if err != nil {
log.Fatal(err)
}
defer func() { _ = client.Close() }()
chain, err := client.Options.GetChain("AAPL",
options.WithExpiry(options.OnExpiration(time.Now().AddDate(0, 1, 0))),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(chain)
}
Output:
func (*Service) GetExpirations ¶
func (s *Service) GetExpirations(symbol string, opts ...ExpirationOption) (*Expirations, error)
GetExpirations is a convenience wrapper for Service.Expirations that uses context.Background() and discards the response metadata. When the API returns 404, GetExpirations returns nil and a nil error.
func (*Service) GetLookup ¶
func (s *Service) GetLookup(underlying string, expiration time.Time, strike float64, optionType OptionType) (string, error)
GetLookup is a convenience wrapper for Service.Lookup that uses context.Background() and discards the response metadata. When the API cannot resolve the contract (404), GetLookup returns an empty string and a nil error.
func (*Service) GetLookupQuery ¶
GetLookupQuery is a convenience wrapper for Service.LookupQuery that uses context.Background() and discards the response metadata. When the API cannot resolve the contract (404), GetLookupQuery returns an empty string and a nil error.
func (*Service) GetQuote ¶
func (s *Service) GetQuote(optionSymbol string, opts ...QuoteOption) (*OptionQuote, error)
GetQuote is a convenience wrapper for Service.Quote that uses context.Background() and discards the response metadata. When the API returns 404, GetQuote returns a nil quote and a nil error.
func (*Service) GetQuoteHistory ¶
func (s *Service) GetQuoteHistory(optionSymbol string, opts ...QuoteOption) ([]OptionQuote, error)
GetQuoteHistory is a convenience wrapper for Service.QuoteHistory that uses context.Background() and discards the response metadata. When the API returns 404, GetQuoteHistory returns a nil slice and a nil error.
func (*Service) GetQuotes ¶
func (s *Service) GetQuotes(optionSymbols []string, opts ...QuoteOption) ([]OptionQuote, error)
GetQuotes is a convenience wrapper for Service.Quotes that uses context.Background() and discards the response metadata. Like Quotes, it fetches the symbols concurrently and omits symbols with no data from the result.
func (*Service) GetQuotesBySymbol ¶
func (s *Service) GetQuotesBySymbol(optionSymbols []string, opts ...QuoteOption) (map[string]*OptionQuote, error)
GetQuotesBySymbol is a convenience wrapper for Service.QuotesBySymbol that uses context.Background() and discards the response metadata. Like QuotesBySymbol, it returns one entry per requested symbol, with a nil value where the API had no data.
func (*Service) Lookup ¶
func (s *Service) Lookup(ctx context.Context, underlying string, expiration time.Time, strike float64, optionType OptionType) (string, *response.Response, error)
Lookup resolves an option contract to its OCC option symbol. It takes the underlying stock symbol, the expiration date, the strike price, and an OptionType (Call or Put), all of which are required, and returns the OCC symbol string (for example "AAPL250117C00150000") suitable for use with Service.Quote and Service.Quotes.
All four arguments are validated before any request is made: a missing underlying, a zero expiration, a strike at or below zero, or an option type other than Call or Put is rejected with a sdkerrors.ValidationError. Without those checks an unset argument would be interpolated into the query verbatim, and the resulting 404 would be reported as no-data — making a malformed call indistinguishable from a contract that does not exist.
If the API cannot resolve the contract (HTTP 404), Lookup returns an empty string, a response whose NoData field is true, and a nil error.
API documentation: https://www.marketdata.app/docs/api/options/lookup
Example:
symbol, _, err := client.Options.Lookup(ctx, "AAPL", expDate, 150.0, options.Call)
Example ¶
ExampleService_Lookup resolves an underlying, expiration, strike, and option type to the corresponding OCC option symbol.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/MarketDataApp/sdk-go/v2/marketdata"
"github.com/MarketDataApp/sdk-go/v2/marketdata/options"
)
func main() {
client, err := marketdata.NewClient()
if err != nil {
log.Fatal(err)
}
defer func() { _ = client.Close() }()
expiration := time.Now().AddDate(0, 1, 0)
symbol, _, err := client.Options.Lookup(context.Background(), "AAPL", expiration, 150, options.Call)
if err != nil {
log.Fatal(err)
}
fmt.Println(symbol)
}
Output:
func (*Service) LookupQuery ¶
func (s *Service) LookupQuery(ctx context.Context, query string) (string, *response.Response, error)
LookupQuery resolves an option contract to its OCC option symbol from a free-form, human-readable description, exactly as the endpoint accepts it — for example "AAPL 7/26/23 $200 Call". The query is required and is sent as a single URL path segment; the endpoint does its own parsing, so the accepted phrasings are the API's, not the SDK's.
Service.Lookup is the typed alternative for the common case where the underlying, expiration, strike, and type are already known separately; it validates those four and assembles the query. Use LookupQuery when the description arrives as text — from a user, a spreadsheet cell, or a broker export — and cannot be decomposed first.
If the API cannot resolve the contract (HTTP 404), LookupQuery returns an empty string, a response whose NoData field is true, and a nil error.
API documentation: https://www.marketdata.app/docs/api/options/lookup
Example:
symbol, _, err := client.Options.LookupQuery(ctx, "AAPL 7/26/23 $200 Call")
func (*Service) Quote ¶
func (s *Service) Quote(ctx context.Context, optionSymbol string, opts ...QuoteOption) (*OptionQuote, *response.Response, error)
Quote fetches a real-time or historical OptionQuote for a single option contract, identified by its OCC option symbol (for example "AAPL250117C00150000"). The option symbol is required; if it is not known, Service.Lookup can resolve one from the underlying, expiration, strike, and type. The optional WithOptionQuoteWindow carries a single OptionQuoteWindow value — options.QuoteOnDate(t), options.QuoteRange(from, to), options.QuoteLastN(n), or options.QuoteLastNUntil(n, to) — to request a historical quote; because it is one value, the API's mutually-exclusive date, from/to, and countback parameters cannot be combined (the API returns HTTP 400 when both a date and a from/to are sent).
A malformed quote window (a zero date, a from after its to, or a countback at or below zero) is rejected with a sdkerrors.ValidationError before any request is made.
Quote returns exactly one quote, as its name says. A window that selects several days — a range, or a countback greater than one — makes the API return one row per day, of which Quote keeps only the first; use Service.QuoteHistory to receive all of them.
An OCC symbol matching no contract is reported as a [NotFoundError]. If the contract exists but the API has no data for the requested window, Quote returns a nil quote, a response whose NoData field is true, and a nil error — an OptionQuote has no meaningful empty value, so callers must check for nil. See the "Missing Data and Unknown Symbols" section of the marketdata package documentation.
API documentation: https://www.marketdata.app/docs/api/options/quotes
Example:
quote, _, err := client.Options.Quote(ctx, "AAPL230120C00150000")
Example ¶
ExampleService_Quote fetches a quote for a single option contract by its OCC option symbol.
package main
import (
"context"
"fmt"
"log"
"github.com/MarketDataApp/sdk-go/v2/marketdata"
)
func main() {
client, err := marketdata.NewClient()
if err != nil {
log.Fatal(err)
}
defer func() { _ = client.Close() }()
quote, _, err := client.Options.Quote(context.Background(), "AAPL250117C00150000")
if err != nil {
log.Fatal(err)
}
fmt.Println(quote)
}
Output:
func (*Service) QuoteHistory ¶
func (s *Service) QuoteHistory(ctx context.Context, optionSymbol string, opts ...QuoteOption) ([]OptionQuote, *response.Response, error)
QuoteHistory fetches every quote the API returns for a single option contract, as a slice in the order the API sent them. It takes the same arguments and options as Service.Quote.
It exists because a historical window can select more than one quote: a QuoteRange spanning several days, or a QuoteLastN/QuoteLastNUntil countback, returns one row per day. Quote returns only the first of those rows, since its contract is a single quote; QuoteHistory returns all of them. For a current quote, or a window that selects a single day, the two are equivalent and QuoteHistory returns a one-element slice.
An OCC symbol matching no contract is reported as a [NotFoundError]. If the contract exists but the window selects nothing, QuoteHistory returns a nil slice (safe to range), a response whose NoData field is true, and a nil error.
API documentation: https://www.marketdata.app/docs/api/options/quotes
Example:
quotes, _, err := client.Options.QuoteHistory(ctx, "AAPL260821C00300000",
options.WithOptionQuoteWindow(options.QuoteLastN(5)))
func (*Service) Quotes ¶
func (s *Service) Quotes(ctx context.Context, optionSymbols []string, opts ...QuoteOption) ([]OptionQuote, *response.Response, error)
Quotes fetches quotes for multiple option contracts identified by their OCC option symbols. At least one symbol is required. The optional QuoteOption values are the same ones Service.Quote accepts and apply to every symbol in the batch, so WithOptionQuoteWindow requests the same historical window across the whole set. The method fans out one concurrent Service.Quote request per symbol; the goroutines draw slots from the client's shared concurrency pool (at most 50 in-flight requests per client across all services), so passing many symbols will not exceed that limit. The results are merged into a single slice in the order the symbols were given.
Symbols the API has no data for, and symbols naming a contract it does not recognize, are both omitted from the result rather than producing an error, so the returned slice may be shorter than the input and gives no indication of which symbols were dropped; use Service.QuotesBySymbol when that distinction matters. This is where the batch methods differ from Service.Quote, which reports an unknown contract as a [NotFoundError]: in a batch a bad symbol is information about that symbol, not a failure of the whole request. If any request fails with a real error, Quotes returns that error and no quotes. The returned response corresponds to one of the individual requests, not an aggregate.
API documentation: https://www.marketdata.app/docs/api/options/quotes
Example:
quotes, _, err := client.Options.Quotes(ctx, []string{"AAPL230120C00150000", "AAPL230120P00150000"})
Example ¶
ExampleService_Quotes fetches quotes for several option contracts concurrently and prints the merged results.
package main
import (
"context"
"fmt"
"log"
"github.com/MarketDataApp/sdk-go/v2/marketdata"
)
func main() {
client, err := marketdata.NewClient()
if err != nil {
log.Fatal(err)
}
defer func() { _ = client.Close() }()
quotes, _, err := client.Options.Quotes(context.Background(), []string{
"AAPL250117C00150000",
"AAPL250117P00150000",
})
if err != nil {
log.Fatal(err)
}
for _, q := range quotes {
fmt.Println(q)
}
}
Output:
func (*Service) QuotesBySymbol ¶
func (s *Service) QuotesBySymbol(ctx context.Context, optionSymbols []string, opts ...QuoteOption) (map[string]*OptionQuote, *response.Response, error)
QuotesBySymbol fetches quotes for multiple option contracts and returns them keyed by the OCC option symbol that was requested. At least one symbol is required. It fetches exactly like Service.Quotes — one concurrent request per symbol, drawn from the client's shared 50-slot pool, with the first hard error cancelling its siblings.
It accepts the same QuoteOption values as Service.Quote, applied to every symbol.
The difference is what happens to contracts the API has no data for, or does not recognize at all. Quotes omits them, so the returned slice is simply shorter than the input and the caller cannot tell which symbols were dropped. QuotesBySymbol returns one map entry for every requested symbol, with a nil value for those, so a missing contract is distinguishable from one that was never asked for. Repeated symbols collapse into a single entry. Neither method reports an unknown contract as an error the way Service.Quote does — see Quotes for why.
If any request fails with a real error, QuotesBySymbol returns that error and no quotes. The returned response corresponds to one of the individual requests, not an aggregate.
API documentation: https://www.marketdata.app/docs/api/options/quotes
Example:
quotes, _, err := client.Options.QuotesBySymbol(ctx, []string{"AAPL230120C00150000", "AAPL230120P00150000"})
for symbol, q := range quotes {
if q == nil {
log.Printf("%s: no data", symbol)
continue
}
...
}
type StrikeFilter ¶
type StrikeFilter interface {
// contains filtered or unexported methods
}
StrikeFilter selects which contracts a Service.Chain request returns by strike price or by delta. It is a sealed union: build it with exactly one of the mode constructors below and pass it to WithStrike. Because a StrikeFilter is a single value, the API's mutually-exclusive contract selectors can never be combined by mistake — the API silently honors strike over delta when both are sent, and that footgun is not expressible here.
The constructors mirror the ways the API accepts a strike filter:
Strike(x) // an exact strike -> strike=x Strikes(x, y, ...) // several exact strikes -> strike=x,y,... StrikeRange(lo, hi)// an inclusive strike range -> strike=lo-hi MinStrike(x) // strikes at or above x -> strike=>=x MaxStrike(x) // strikes at or below x -> strike=<=x StrikeExpr(expr) // a raw strike expression -> strike=expr ByDelta(d) // the strike nearest delta d -> delta=d ByDeltas(c, d, ...)// the strikes nearest each -> delta=c,d,...
Strike prices must be greater than zero and a range's low must not exceed its high; a delta must be non-zero and within [-1, 1] (puts have negative delta). The list forms require at least one value and apply the same rules to every element. Values are checked before any request is made.
func ByDelta ¶
func ByDelta(d float64) StrikeFilter
ByDelta selects the strikes nearest the given delta (delta=d). The API filters on the ABSOLUTE value of delta and always returns both sides (calls and puts), so ByDelta does not choose a side — combine it with WithSide to keep only calls or puts.
The filter can silently do nothing. If ANY contract in the chain the API fetched carries a null delta, the whole filter is skipped and the full chain comes back with a 200 and no signal (https://github.com/MarketData-App/api/issues/352). Null greeks are not rare — illiquid strikes, freshly listed contracts, provider metadata rot — so this fires on some symbols and expirations and not others.
It reads as a side limitation because that is how it first presented: on 2026-08-20 delta=0.30&side=call returned one contract at 0.338 while side=put returned 99 and no side at all returned 198, which looked like "calls only". It is not — on 2026-08-26 the same query returned one contract per side and two with no side, correctly filtered. What differed was whether the fetched chain happened to contain a null delta. Check the result rather than assuming either behavior. Tracked in integration/discrepancy_test.go.
Delta is mutually exclusive with strike (the API silently honors strike when both are sent), so it is a mode of StrikeFilter rather than a separate option. d must be non-zero and within [-1, 1] (negative values are accepted and, per the absolute-value rule, behave the same as their positive counterpart).
func ByDeltas ¶
func ByDeltas(deltas ...float64) StrikeFilter
ByDeltas selects the strikes nearest each of the given deltas (delta=c,d,...), for example the 0.16 and 0.30 deltas of a strangle in one request. Like ByDelta it filters on the ABSOLUTE value of delta and returns both sides — combine it with WithSide to keep only calls or puts. Like ByDelta the filter is silently dropped when the fetched chain contains a null delta; see ByDelta. At least one delta is required and every value must be non-zero and within [-1, 1].
func MaxStrike ¶
func MaxStrike(x float64) StrikeFilter
MaxStrike limits the chain to strikes at or below x (strike=<=x).
func MinStrike ¶
func MinStrike(x float64) StrikeFilter
MinStrike limits the chain to strikes at or above x (strike=>=x).
func Strike ¶
func Strike(x float64) StrikeFilter
Strike limits the chain to contracts at an exact strike price (strike=x).
func StrikeExpr ¶
func StrikeExpr(expr string) StrikeFilter
StrikeExpr sets the strike filter using the API's raw expression syntax, passed through verbatim (strike=expr): an exact strike ("150"), an inclusive range ("140-160"), or a one-sided bound (">=140", "<=160"). It is an escape hatch for expressions the typed constructors do not cover.
func StrikeRange ¶
func StrikeRange(lo, hi float64) StrikeFilter
StrikeRange limits the chain to strikes between lo and hi inclusive (strike=lo-hi).
func Strikes ¶
func Strikes(strikes ...float64) StrikeFilter
Strikes limits the chain to an explicit set of exact strike prices (strike=x,y,z), returning both sides at each one unless WithSide narrows it. Use it to price a spread or a specific set of legs in a single request rather than one call per strike. At least one strike is required and every value must be greater than zero.