package crypto import ( "encoding/json" decimal "github.com/alpacahq/alpacadecimal" "s1d3sw1ped/robinhood-agentic-mcp/internal/wire" ) func (o *Order) UnmarshalJSON(b []byte) error { var row struct { ID string `json:"id"` Symbol string `json:"symbol"` Side string `json:"side"` State string `json:"state"` Status string `json:"status"` Quantity any `json:"quantity"` } if err := json.Unmarshal(b, &row); err != nil { return err } o.ID, o.Symbol, o.Side = row.ID, row.Symbol, row.Side o.State = row.State if o.State == "" { o.State = row.Status } var err error o.Qty, err = firstDec(row.Quantity) return err } func parseOrders(raw json.RawMessage) ([]Order, error) { rows, _, err := wire.UnmarshalRows[Order](raw, "results", "orders") if err != nil { return nil, err } if len(rows) > 0 { return rows, nil } var one Order if err := json.Unmarshal(wire.Unwrap(raw), &one); err != nil { return nil, err } if one.ID != "" { return []Order{one}, nil } return nil, nil } func (r *PairsResult) UnmarshalJSON(b []byte) error { type row struct { ID string `json:"id"` Symbol string `json:"symbol"` } rows, next, err := wire.UnmarshalRows[row](b, "results", "pairs") if err != nil { return err } r.NextCursor = next r.Pairs = make([]CurrencyPair, 0, len(rows)) for _, row := range rows { r.Pairs = append(r.Pairs, CurrencyPair{ID: row.ID, Symbol: row.Symbol}) } return nil } func (r *QuotesResult) UnmarshalJSON(b []byte) error { type row struct { Symbol string `json:"symbol"` Bid any `json:"bid"` Ask any `json:"ask"` Mark any `json:"mark"` PrevClose any `json:"open_price"` Close any `json:"previous_close"` } rows, _, err := wire.UnmarshalRows[row](b, "results", "quotes") if err != nil { return err } r.Quotes = make([]CryptoQuote, 0, len(rows)) for _, row := range rows { bid, err := firstDec(row.Bid) if err != nil { return err } ask, err := firstDec(row.Ask) if err != nil { return err } mark, err := firstDec(row.Mark) if err != nil { return err } prev, err := firstDec(row.PrevClose, row.Close) if err != nil { return err } r.Quotes = append(r.Quotes, CryptoQuote{Symbol: row.Symbol, Bid: bid, Ask: ask, Mark: mark, PrevClose: prev}) } return nil } func (r *PositionsResult) UnmarshalJSON(b []byte) error { type row struct { Symbol string `json:"symbol"` Asset string `json:"asset"` Quantity any `json:"quantity"` CostBasis any `json:"cost_basis"` } rows, next, err := wire.UnmarshalRows[row](b, "results", "positions") if err != nil { return err } r.NextCursor = next r.Positions = make([]CryptoPosition, 0, len(rows)) for _, row := range rows { sym := row.Symbol if sym == "" { sym = row.Asset } qty, err := firstDec(row.Quantity) if err != nil { return err } cost, err := firstDec(row.CostBasis) if err != nil { return err } r.Positions = append(r.Positions, CryptoPosition{Symbol: sym, Quantity: qty, CostBasis: cost}) } return nil } func (r *OrdersResult) UnmarshalJSON(b []byte) error { rows, next, err := wire.UnmarshalRows[Order](b, "results", "orders") if err != nil { return err } r.Orders = rows r.NextCursor = next return nil } func (r *PreviewResult) UnmarshalJSON(b []byte) error { var wrap struct { Errors []string `json:"errors"` Warnings []string `json:"warnings"` Quantity any `json:"quantity"` Price any `json:"price"` } if err := json.Unmarshal(wire.Unwrap(b), &wrap); err != nil { return err } r.Errors, r.Warnings = wrap.Errors, wrap.Warnings var err error if r.Quantity, err = firstDec(wrap.Quantity); err != nil { return err } r.Price, err = firstDec(wrap.Price) return err } func firstDec(vs ...any) (decimal.Decimal, error) { for _, v := range vs { if v == nil { continue } if s, ok := v.(string); ok && s == "" { continue } return wire.Dec(v) } return decimal.Zero, nil }