feat: add options MCP methods
This commit is contained in:
+271
@@ -0,0 +1,271 @@
|
||||
package options
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"s1d3sw1ped/robinhood-agentic-mcp/client"
|
||||
"s1d3sw1ped/robinhood-agentic-mcp/internal/wire"
|
||||
)
|
||||
|
||||
const (
|
||||
toolChains = "get_option_chains"
|
||||
toolInstruments = "get_option_instruments"
|
||||
toolQuotes = "get_option_quotes"
|
||||
toolPositions = "get_option_positions"
|
||||
toolOrders = "get_option_orders"
|
||||
toolHistoricals = "get_option_historicals"
|
||||
)
|
||||
|
||||
// ChainsRequest is the argument set for get_option_chains.
|
||||
type ChainsRequest struct {
|
||||
IDs string
|
||||
UnderlyingSymbol string
|
||||
}
|
||||
|
||||
// ChainsResult is the parsed get_option_chains payload.
|
||||
type ChainsResult struct{}
|
||||
|
||||
// InstrumentsRequest is the argument set for get_option_instruments.
|
||||
type InstrumentsRequest struct {
|
||||
ChainID string
|
||||
ChainSymbol string
|
||||
ExpirationDates string
|
||||
StrikePrice string
|
||||
Type string
|
||||
State string
|
||||
Tradability string
|
||||
IDs string
|
||||
Cursor string
|
||||
}
|
||||
|
||||
// InstrumentsResult is the parsed get_option_instruments payload.
|
||||
type InstrumentsResult struct{}
|
||||
|
||||
// QuotesRequest is the argument set for get_option_quotes.
|
||||
type QuotesRequest struct {
|
||||
InstrumentIDs []string
|
||||
}
|
||||
|
||||
// QuotesResult is the parsed get_option_quotes payload.
|
||||
type QuotesResult struct{}
|
||||
|
||||
// PositionsRequest is the argument set for get_option_positions.
|
||||
type PositionsRequest struct {
|
||||
AccountNumber string
|
||||
Nonzero bool
|
||||
ChainIDs string
|
||||
OptionIDs string
|
||||
Type string
|
||||
OptionType string
|
||||
ExpirationDate string
|
||||
ExpirationDateLTE string
|
||||
ExpirationDateGTE string
|
||||
Cursor string
|
||||
}
|
||||
|
||||
// PositionsResult is the parsed get_option_positions payload.
|
||||
type PositionsResult struct{}
|
||||
|
||||
// OrdersRequest is the argument set for get_option_orders.
|
||||
type OrdersRequest struct {
|
||||
AccountNumber string
|
||||
OrderID string
|
||||
State string
|
||||
CreatedAtGTE string
|
||||
ChainIDs string
|
||||
UnderlyingType string
|
||||
PlacedAgent string
|
||||
Cursor string
|
||||
}
|
||||
|
||||
// OrdersResult is the parsed get_option_orders payload.
|
||||
type OrdersResult struct{}
|
||||
|
||||
// HistoricalsRequest is the argument set for get_option_historicals.
|
||||
type HistoricalsRequest struct {
|
||||
InstrumentIDs []string
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
Interval string
|
||||
Bounds string
|
||||
}
|
||||
|
||||
// HistoricalsResult is the parsed get_option_historicals payload.
|
||||
type HistoricalsResult struct{}
|
||||
|
||||
// Chains calls get_option_chains.
|
||||
func (c *Client) Chains(ctx context.Context, req ChainsRequest) (ChainsResult, error) {
|
||||
args := map[string]any{}
|
||||
if req.IDs != "" {
|
||||
args["ids"] = req.IDs
|
||||
}
|
||||
if req.UnderlyingSymbol != "" {
|
||||
args["underlying_symbol"] = req.UnderlyingSymbol
|
||||
}
|
||||
var out ChainsResult
|
||||
if err := c.parse(ctx, toolChains, args, &out); err != nil {
|
||||
return ChainsResult{}, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Instruments calls get_option_instruments.
|
||||
func (c *Client) Instruments(ctx context.Context, req InstrumentsRequest) (InstrumentsResult, error) {
|
||||
args := map[string]any{}
|
||||
if req.ChainID != "" {
|
||||
args["chain_id"] = req.ChainID
|
||||
}
|
||||
if req.ChainSymbol != "" {
|
||||
args["chain_symbol"] = req.ChainSymbol
|
||||
}
|
||||
if req.ExpirationDates != "" {
|
||||
args["expiration_dates"] = req.ExpirationDates
|
||||
}
|
||||
if req.StrikePrice != "" {
|
||||
args["strike_price"] = req.StrikePrice
|
||||
}
|
||||
if req.Type != "" {
|
||||
args["type"] = req.Type
|
||||
}
|
||||
if req.State != "" {
|
||||
args["state"] = req.State
|
||||
}
|
||||
if req.Tradability != "" {
|
||||
args["tradability"] = req.Tradability
|
||||
}
|
||||
if req.IDs != "" {
|
||||
args["ids"] = req.IDs
|
||||
}
|
||||
if req.Cursor != "" {
|
||||
args["cursor"] = req.Cursor
|
||||
}
|
||||
var out InstrumentsResult
|
||||
if err := c.parse(ctx, toolInstruments, args, &out); err != nil {
|
||||
return InstrumentsResult{}, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Quotes calls get_option_quotes.
|
||||
func (c *Client) Quotes(ctx context.Context, req QuotesRequest) (QuotesResult, error) {
|
||||
args := map[string]any{}
|
||||
if len(req.InstrumentIDs) > 0 {
|
||||
args["instrument_ids"] = req.InstrumentIDs
|
||||
}
|
||||
var out QuotesResult
|
||||
if err := c.parse(ctx, toolQuotes, args, &out); err != nil {
|
||||
return QuotesResult{}, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Positions calls get_option_positions.
|
||||
func (c *Client) Positions(ctx context.Context, req PositionsRequest) (PositionsResult, error) {
|
||||
args := map[string]any{}
|
||||
if req.AccountNumber != "" {
|
||||
args["account_number"] = req.AccountNumber
|
||||
}
|
||||
if req.Nonzero {
|
||||
args["nonzero"] = true
|
||||
}
|
||||
if req.ChainIDs != "" {
|
||||
args["chain_ids"] = req.ChainIDs
|
||||
}
|
||||
if req.OptionIDs != "" {
|
||||
args["option_ids"] = req.OptionIDs
|
||||
}
|
||||
if req.Type != "" {
|
||||
args["type"] = req.Type
|
||||
}
|
||||
if req.OptionType != "" {
|
||||
args["option_type"] = req.OptionType
|
||||
}
|
||||
if req.ExpirationDate != "" {
|
||||
args["expiration_date"] = req.ExpirationDate
|
||||
}
|
||||
if req.ExpirationDateLTE != "" {
|
||||
args["expiration_date_lte"] = req.ExpirationDateLTE
|
||||
}
|
||||
if req.ExpirationDateGTE != "" {
|
||||
args["expiration_date_gte"] = req.ExpirationDateGTE
|
||||
}
|
||||
if req.Cursor != "" {
|
||||
args["cursor"] = req.Cursor
|
||||
}
|
||||
var out PositionsResult
|
||||
if err := c.parse(ctx, toolPositions, args, &out); err != nil {
|
||||
return PositionsResult{}, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Orders calls get_option_orders.
|
||||
func (c *Client) Orders(ctx context.Context, req OrdersRequest) (OrdersResult, error) {
|
||||
args := map[string]any{}
|
||||
if req.AccountNumber != "" {
|
||||
args["account_number"] = req.AccountNumber
|
||||
}
|
||||
if req.OrderID != "" {
|
||||
args["order_id"] = req.OrderID
|
||||
}
|
||||
if req.State != "" {
|
||||
args["state"] = req.State
|
||||
}
|
||||
if req.CreatedAtGTE != "" {
|
||||
args["created_at_gte"] = req.CreatedAtGTE
|
||||
}
|
||||
if req.ChainIDs != "" {
|
||||
args["chain_ids"] = req.ChainIDs
|
||||
}
|
||||
if req.UnderlyingType != "" {
|
||||
args["underlying_type"] = req.UnderlyingType
|
||||
}
|
||||
if req.PlacedAgent != "" {
|
||||
args["placed_agent"] = req.PlacedAgent
|
||||
}
|
||||
if req.Cursor != "" {
|
||||
args["cursor"] = req.Cursor
|
||||
}
|
||||
var out OrdersResult
|
||||
if err := c.parse(ctx, toolOrders, args, &out); err != nil {
|
||||
return OrdersResult{}, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Historicals calls get_option_historicals.
|
||||
func (c *Client) Historicals(ctx context.Context, req HistoricalsRequest) (HistoricalsResult, error) {
|
||||
args := map[string]any{
|
||||
"start_time": req.StartTime.UTC().Format(time.RFC3339),
|
||||
}
|
||||
if len(req.InstrumentIDs) > 0 {
|
||||
args["instrument_ids"] = req.InstrumentIDs
|
||||
}
|
||||
if !req.EndTime.IsZero() {
|
||||
args["end_time"] = req.EndTime.UTC().Format(time.RFC3339)
|
||||
}
|
||||
if req.Interval != "" {
|
||||
args["interval"] = req.Interval
|
||||
}
|
||||
if req.Bounds != "" {
|
||||
args["bounds"] = req.Bounds
|
||||
}
|
||||
var out HistoricalsResult
|
||||
if err := c.parse(ctx, toolHistoricals, args, &out); err != nil {
|
||||
return HistoricalsResult{}, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Client) parse(ctx context.Context, tool string, args map[string]any, dest any) error {
|
||||
raw, err := c.c.Call(ctx, tool, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(wire.Unwrap(raw), dest); err != nil {
|
||||
return client.ToolErrorf(tool, "parse: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user