package tastytrade import ( "encoding/json" "fmt" "net/url" ) type FutureETFEquivalent struct { Symbol string `json:"symbol"` ShareQuantity int `json:"share-quantity"` } type FutureProduct struct { RootSymbol string `json:"root-symbol"` Code string `json:"code"` Description string `json:"description"` ClearingCode string `json:"clearing-code"` ClearingExchangeCode string `json:"clearing-exchange-code"` ClearportCode string `json:"clearport-code"` LegacyCode string `json:"legacy-code"` Exchange string `json:"exchange"` LegacyExchangeCode string `json:"legacy-exchange-code"` ProductType string `json:"product-type"` ListedMonths []string `json:"listed-months"` ActiveMonths []string `json:"active-months"` NotionalMultiplier string `json:"notional-multiplier"` TickSize string `json:"tick-size"` DisplayFactor string `json:"display-factor"` StreamerExchangeCode string `json:"streamer-exchange-code"` SmallNotional bool `json:"small-notional"` BackMonthFirstCalendarSymbol bool `json:"back-month-first-calendar-symbol"` FirstNotice bool `json:"first-notice"` CashSettled bool `json:"cash-settled"` SecurityGroup string `json:"security-group"` MarketSector string `json:"market-sector"` Roll struct { Name string `json:"name"` ActiveCount int `json:"active-count"` CashSettled bool `json:"cash-settled"` BusinessDaysOffset int `json:"business-days-offset"` FirstNotice bool `json:"first-notice"` } `json:"roll"` } type TickSize struct { Value string `json:"value"` Threshold string `json:"threshold,omitempty"` Symbol string `json:"symbol,omitempty"` } type Future struct { Symbol string `json:"symbol"` ProductCode string `json:"product-code"` ContractSize string `json:"contract-size"` TickSize string `json:"tick-size"` NotionalMultiplier string `json:"notional-multiplier"` MainFraction string `json:"main-fraction"` SubFraction string `json:"sub-fraction"` DisplayFactor string `json:"display-factor"` LastTradeDate string `json:"last-trade-date"` ExpirationDate string `json:"expiration-date"` ClosingOnlyDate string `json:"closing-only-date"` Active bool `json:"active"` ActiveMonth bool `json:"active-month"` NextActiveMonth bool `json:"next-active-month"` IsClosingOnly bool `json:"is-closing-only"` StopsTradingAt string `json:"stops-trading-at"` ExpiresAt string `json:"expires-at"` ProductGroup string `json:"product-group"` Exchange string `json:"exchange"` RollTargetSymbol string `json:"roll-target-symbol"` StreamerExchangeCode string `json:"streamer-exchange-code"` StreamerSymbol string `json:"streamer-symbol"` BackMonthFirstCalendarSymbol bool `json:"back-month-first-calendar-symbol"` IsTradeable bool `json:"is-tradeable"` FutureETFEquivalent FutureETFEquivalent `json:"future-etf-equivalent"` FutureProduct FutureProduct `json:"future-product"` TickSizes []TickSize `json:"tick-sizes"` OptionTickSizes []TickSize `json:"option-tick-sizes"` SpreadTickSizes []TickSize `json:"spread-tick-sizes"` } type FuturesQueryResponse struct { Data struct { Items []Future `json:"items"` } `json:"data"` } type FuturesQueryParams struct { Symbol []string `json:"symbol"` ProductCode []string `json:"product-code"` } type FutureResponse struct { Data Future `json:"data"` Context string `json:"context"` } type FutureOptionProduct struct { RootSymbol string `json:"root-symbol"` CashSettled bool `json:"cash-settled"` Code string `json:"code"` LegacyCode string `json:"legacy-code"` ClearportCode string `json:"clearport-code"` ClearingCode string `json:"clearing-code"` ClearingExchangeCode string `json:"clearing-exchange-code"` ClearingPriceMultiplier string `json:"clearing-price-multiplier"` DisplayFactor string `json:"display-factor"` Exchange string `json:"exchange"` ProductType string `json:"product-type"` ExpirationType string `json:"expiration-type"` SettlementDelayDays int `json:"settlement-delay-days"` IsRollover bool `json:"is-rollover"` MarketSector string `json:"market-sector"` } type FutureProductsResponse struct { Data struct { Items []FutureProduct `json:"items"` } `json:"data"` Context string `json:"context"` } type FutureProductResponse struct { Data FutureProduct `json:"data"` Context string `json:"context"` } type FuturesOptionExpirationNested struct { UnderlyingSymbol string `json:"underlying-symbol"` RootSymbol string `json:"root-symbol"` OptionRootSymbol string `json:"option-root-symbol"` OptionContractSymbol string `json:"option-contract-symbol"` Asset string `json:"asset"` ExpirationDate string `json:"expiration-date"` DaysToExpiration int `json:"days-to-expiration"` ExpirationType string `json:"expiration-type"` SettlementType string `json:"settlement-type"` NotionalValue string `json:"notional-value"` DisplayFactor string `json:"display-factor"` StrikeFactor string `json:"strike-factor"` StopsTradingAt string `json:"stops-trading-at"` ExpiresAt string `json:"expires-at"` TickSizes []TickSize `json:"tick-sizes"` Strikes []StrikeNested `json:"strikes"` } type OptionChain struct { UnderlyingSymbol string `json:"underlying-symbol"` RootSymbol string `json:"root-symbol"` ExerciseStyle string `json:"exercise-style"` Expirations []FuturesOptionExpirationNested `json:"expirations"` } type FutureOptionChainsNestedData struct { Futures []Future `json:"futures"` OptionChains []OptionChain `json:"option-chains"` } type FutureOptionChainsNestedResponse struct { Data FutureOptionChainsNestedData `json:"data"` Context string `json:"context"` } type FutureOption struct { Symbol string `json:"symbol"` UnderlyingSymbol string `json:"underlying-symbol"` ProductCode string `json:"product-code"` ExpirationDate string `json:"expiration-date"` RootSymbol string `json:"root-symbol"` OptionRootSymbol string `json:"option-root-symbol"` StrikePrice string `json:"strike-price"` Exchange string `json:"exchange"` ExchangeSymbol string `json:"exchange-symbol"` StreamerSymbol string `json:"streamer-symbol"` OptionType string `json:"option-type"` ExerciseStyle string `json:"exercise-style"` IsVanilla bool `json:"is-vanilla"` IsPrimaryDeliverable bool `json:"is-primary-deliverable"` FuturePriceRatio string `json:"future-price-ratio"` Multiplier string `json:"multiplier"` UnderlyingCount string `json:"underlying-count"` IsConfirmed bool `json:"is-confirmed"` NotionalValue string `json:"notional-value"` DisplayFactor string `json:"display-factor"` SecurityExchange string `json:"security-exchange"` SxID string `json:"sx-id"` SettlementType string `json:"settlement-type"` StrikeFactor string `json:"strike-factor"` MaturityDate string `json:"maturity-date"` IsExercisableWeekly bool `json:"is-exercisable-weekly"` LastTradeTime string `json:"last-trade-time"` DaysToExpiration int `json:"days-to-expiration"` IsClosingOnly bool `json:"is-closing-only"` Active bool `json:"active"` StopsTradingAt string `json:"stops-trading-at"` ExpiresAt string `json:"expires-at"` FutureOptionProduct FutureOptionProduct `json:"future-option-product"` } type FutureOptionChainsDetailedResponse struct { Data struct { Items []FutureOption `json:"items"` } `json:"data"` Context string `json:"context"` } type FutureOptionsDetailedResponse struct { Data struct { Items []FutureOption `json:"items"` } `json:"data"` Context string `json:"context"` } type FutureOptionProductsResponse struct { Data struct { Items []FutureOptionProduct `json:"items"` } `json:"data"` Context string `json:"context"` } type FutureOptionProductDetailedResponse struct { Data FutureOptionProduct `json:"data"` Context string `json:"context"` } type FutureOptionsQueryParams struct { Symbol []string `json:"symbol"` OptionRootSymbol string `json:"option-root-symbol"` ExpirationDate string `json:"expiration-date"` OptionType string `json:"option-type"` StrikePrice float64 `json:"strike-price"` } type FutureOptionDetailedResponse struct { Data FutureOption `json:"data"` Context string `json:"context"` } // QueryFutures retrieves a list of futures func (api *TastytradeAPI) QueryFutures(params *FuturesQueryParams) (FuturesQueryResponse, error) { urlVal := fmt.Sprintf("%s/instruments/futures", api.host) if params != nil { queryParams := url.Values{} for _, symbol := range params.Symbol { queryParams.Add("symbol[]", symbol) } for _, productCode := range params.ProductCode { queryParams.Add("product-code[]", productCode) } urlVal = fmt.Sprintf("%s?%s", urlVal, queryParams.Encode()) } data, err := api.fetchData(urlVal) if err != nil { return FuturesQueryResponse{}, err } var response FuturesQueryResponse jsonData, err := json.Marshal(data) if err != nil { return FuturesQueryResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FuturesQueryResponse{}, err } return response, nil } // GetFuture retrieves data for a specific future symbol func (api *TastytradeAPI) GetFuture(symbol string) (FutureResponse, error) { urlVal := fmt.Sprintf("%s/instruments/futures/%s", api.host, url.PathEscape(symbol)) data, err := api.fetchData(urlVal) if err != nil { return FutureResponse{}, err } var response FutureResponse jsonData, err := json.Marshal(data) if err != nil { return FutureResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureResponse{}, err } return response, nil } // ListFutureProducts retrieves a list of future products func (api *TastytradeAPI) ListFutureProducts() (FutureProductsResponse, error) { urlVal := fmt.Sprintf("%s/instruments/future-products", api.host) data, err := api.fetchData(urlVal) if err != nil { return FutureProductsResponse{}, err } var response FutureProductsResponse jsonData, err := json.Marshal(data) if err != nil { return FutureProductsResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureProductsResponse{}, err } return response, nil } // GetFutureProduct retrieves data for a specific future product func (api *TastytradeAPI) GetFutureProduct(exchange string, symbol string) (FutureProductResponse, error) { urlVal := fmt.Sprintf("%s/instruments/future-products/%s/%s", api.host, exchange, url.PathEscape(symbol)) data, err := api.fetchData(urlVal) if err != nil { return FutureProductResponse{}, err } var response FutureProductResponse jsonData, err := json.Marshal(data) if err != nil { return FutureProductResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureProductResponse{}, err } return response, nil } // ListFutureOptionChainsNested retrieves nested future option chain data for a specific symbol func (api *TastytradeAPI) ListFutureOptionChainsNested(symbol string) (FutureOptionChainsNestedResponse, error) { urlVal := fmt.Sprintf("%s/futures-option-chains/%s/nested", api.host, symbol) data, err := api.fetchData(urlVal) if err != nil { return FutureOptionChainsNestedResponse{}, err } var response FutureOptionChainsNestedResponse jsonData, err := json.Marshal(data) if err != nil { return FutureOptionChainsNestedResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureOptionChainsNestedResponse{}, err } return response, nil } // ListFutureOptionChainsDetailed retrieves detailed future option chain data for a specific symbol func (api *TastytradeAPI) ListFutureOptionChainsDetailed(symbol string) (FutureOptionChainsDetailedResponse, error) { urlVal := fmt.Sprintf("%s/futures-option-chains/%s", api.host, symbol) data, err := api.fetchData(urlVal) if err != nil { return FutureOptionChainsDetailedResponse{}, err } var response FutureOptionChainsDetailedResponse jsonData, err := json.Marshal(data) if err != nil { return FutureOptionChainsDetailedResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureOptionChainsDetailedResponse{}, err } return response, nil } // ListFutureOptions retrieves future option data for a specific symbol with query parameters func (api *TastytradeAPI) ListFutureOptions(params *FutureOptionsQueryParams) (FutureOptionsDetailedResponse, error) { urlVal := fmt.Sprintf("%s/instruments/future-options", api.host) if params != nil { queryParams := url.Values{} for _, symbol := range params.Symbol { queryParams.Add("symbol[]", symbol) } if params.OptionRootSymbol != "" { queryParams.Add("option-root-symbol", params.OptionRootSymbol) } if params.ExpirationDate != "" { queryParams.Add("expiration-date", params.ExpirationDate) } if params.OptionType != "" { queryParams.Add("option-type", params.OptionType) } if params.StrikePrice != 0 { queryParams.Add("strike-price", fmt.Sprintf("%.2f", params.StrikePrice)) } urlVal = fmt.Sprintf("%s?%s", urlVal, queryParams.Encode()) } data, err := api.fetchData(urlVal) if err != nil { return FutureOptionsDetailedResponse{}, err } var response FutureOptionsDetailedResponse jsonData, err := json.Marshal(data) if err != nil { return FutureOptionsDetailedResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureOptionsDetailedResponse{}, err } return response, nil } // GetFutureOption retrieves data for a specific future option symbol func (api *TastytradeAPI) GetFutureOption(symbol string) (FutureOptionDetailedResponse, error) { urlVal := fmt.Sprintf("%s/instruments/future-options/%s", api.host, url.PathEscape(symbol)) data, err := api.fetchData(urlVal) if err != nil { return FutureOptionDetailedResponse{}, err } var response FutureOptionDetailedResponse jsonData, err := json.Marshal(data) if err != nil { return FutureOptionDetailedResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureOptionDetailedResponse{}, err } return response, nil } // ListFutureOptionProducts retrieves a list of future option products func (api *TastytradeAPI) ListFutureOptionProducts() (FutureOptionProductsResponse, error) { urlVal := fmt.Sprintf("%s/instruments/future-option-products", api.host) data, err := api.fetchData(urlVal) if err != nil { return FutureOptionProductsResponse{}, err } var response FutureOptionProductsResponse jsonData, err := json.Marshal(data) if err != nil { return FutureOptionProductsResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureOptionProductsResponse{}, err } return response, nil } // GetFutureOptionProduct retrieves data for a specific future option product func (api *TastytradeAPI) GetFutureOptionProduct(exchange string, rootSymbol string) (FutureOptionProductDetailedResponse, error) { urlVal := fmt.Sprintf("%s/instruments/future-option-products/%s/%s", api.host, exchange, rootSymbol) data, err := api.fetchData(urlVal) if err != nil { return FutureOptionProductDetailedResponse{}, err } var response FutureOptionProductDetailedResponse jsonData, err := json.Marshal(data) if err != nil { return FutureOptionProductDetailedResponse{}, err } err = json.Unmarshal(jsonData, &response) if err != nil { return FutureOptionProductDetailedResponse{}, err } return response, nil }