package equity import ( "encoding/json" "time" "s1d3sw1ped/robinhood-agentic-mcp/internal/wire" ) func (r *PositionsResult) UnmarshalJSON(b []byte) error { type row struct { Symbol string `json:"symbol"` Quantity any `json:"quantity"` Qty any `json:"qty"` AverageBuyPrice any `json:"average_buy_price"` AvgCost any `json:"avg_cost"` } rows, next, err := wire.UnmarshalRows[row](b, "positions", "results") if err != nil { return err } r.NextCursor = next r.Positions = make([]Position, 0, len(rows)) for _, row := range rows { qty, err := firstDec(row.Quantity, row.Qty) if err != nil { return err } avg, err := firstDec(row.AverageBuyPrice, row.AvgCost) if err != nil { return err } r.Positions = append(r.Positions, Position{Symbol: row.Symbol, Qty: qty, AvgCost: avg}) } return nil } func (r *TaxLotsResult) UnmarshalJSON(b []byte) error { type row struct { OpenLotID string `json:"open_lot_id"` ID string `json:"id"` Quantity any `json:"quantity"` QuantityAvailable any `json:"quantity_available"` CostBasis any `json:"cost_basis"` AcquiredAt string `json:"acquired_at"` AcquisitionDate string `json:"acquisition_date"` Term string `json:"term"` HoldingPeriod string `json:"holding_period"` } rows, next, err := wire.UnmarshalRows[row](b, "tax_lots", "lots", "results") if err != nil { return err } r.NextCursor = next r.Lots = make([]TaxLotRow, 0, len(rows)) for _, row := range rows { id := row.OpenLotID if id == "" { id = row.ID } qty, err := firstDec(row.Quantity) if err != nil { return err } avail, err := firstDec(row.QuantityAvailable) if err != nil { return err } cost, err := firstDec(row.CostBasis) if err != nil { return err } when := row.AcquiredAt if when == "" { when = row.AcquisitionDate } term := row.Term if term == "" { term = row.HoldingPeriod } r.Lots = append(r.Lots, TaxLotRow{ OpenLotID: id, Quantity: qty, QuantityAvail: avail, CostBasis: cost, AcquiredAt: when, Term: term, }) } return nil } func (r *OrdersResult) UnmarshalJSON(b []byte) error { rows, next, err := wire.UnmarshalRows[Order](b, "orders", "results") if err != nil { return err } r.NextCursor = next if len(rows) == 0 { var one Order if err := json.Unmarshal(wire.Unwrap(b), &one); err == nil && one.ID != "" { rows = []Order{one} } } r.Orders = rows return nil } func (r *TradabilityResult) UnmarshalJSON(b []byte) error { type row struct { Symbol string `json:"symbol"` Tradable bool `json:"tradable"` IsTradable bool `json:"is_tradable"` Fractional bool `json:"fractional"` FractionalOk bool `json:"fractional_tradable"` FractionalTrad bool `json:"fractionally_tradable"` } rows, _, err := wire.UnmarshalRows[row](b, "results", "tradability", "instruments") if err != nil { return err } if len(rows) == 0 { var one row if json.Unmarshal(wire.Unwrap(b), &one) == nil && (one.Symbol != "" || one.Tradable || one.IsTradable || one.Fractional) { rows = []row{one} } } r.Symbols = make([]SymbolTradability, 0, len(rows)) for _, row := range rows { r.Symbols = append(r.Symbols, SymbolTradability{ Symbol: row.Symbol, Tradable: row.Tradable || row.IsTradable, Fractional: row.Fractional || row.FractionalOk || row.FractionalTrad, }) } return nil } func (r *FundamentalsResult) UnmarshalJSON(b []byte) error { type row struct { Symbol string `json:"symbol"` AverageVolume any `json:"average_volume"` AvgVolume any `json:"avg_volume"` Type string `json:"type"` Instrument string `json:"instrument_kind"` MarketCap any `json:"market_cap"` PE any `json:"pe_ratio"` High52 any `json:"high_52_weeks"` Low52 any `json:"low_52_weeks"` } rows, _, err := wire.UnmarshalRows[row](b, "fundamentals", "results") if err != nil { return err } if len(rows) == 0 { var one row if json.Unmarshal(wire.Unwrap(b), &one) == nil && one.Symbol != "" { rows = []row{one} } } r.Fundamentals = make([]Fundamentals, 0, len(rows)) for _, row := range rows { kind := row.Instrument if kind == "" { kind = row.Type } avg, err := firstDec(row.AverageVolume, row.AvgVolume) if err != nil { return err } cap, err := firstDec(row.MarketCap) if err != nil { return err } pe, err := firstDec(row.PE) if err != nil { return err } hi, err := firstDec(row.High52) if err != nil { return err } lo, err := firstDec(row.Low52) if err != nil { return err } r.Fundamentals = append(r.Fundamentals, Fundamentals{ Symbol: row.Symbol, AvgVolume: avg, InstrumentKind: kind, MarketCap: cap, PE: pe, High52Week: hi, Low52Week: lo, }) } return nil } func (r *PriceBookResult) UnmarshalJSON(b []byte) error { type level struct { Price any `json:"price"` Quantity any `json:"quantity"` Size any `json:"size"` } type book struct { Symbol string `json:"symbol"` Bids []level `json:"bids"` Asks []level `json:"asks"` } rows, _, err := wire.UnmarshalRows[book](b, "books", "price_books", "results") if err != nil { return err } if len(rows) == 0 { var one book if json.Unmarshal(wire.Unwrap(b), &one) == nil && one.Symbol != "" { rows = []book{one} } } levels := func(in []level) ([]BookLevel, error) { out := make([]BookLevel, 0, len(in)) for _, lv := range in { px, err := firstDec(lv.Price) if err != nil { return nil, err } qty, err := firstDec(lv.Quantity, lv.Size) if err != nil { return nil, err } out = append(out, BookLevel{Price: px, Quantity: qty}) } return out, nil } r.Books = make([]PriceBook, 0, len(rows)) for _, row := range rows { bids, err := levels(row.Bids) if err != nil { return err } asks, err := levels(row.Asks) if err != nil { return err } r.Books = append(r.Books, PriceBook{Symbol: row.Symbol, Bids: bids, Asks: asks}) } return nil } func (r *TechnicalIndicatorsResult) UnmarshalJSON(b []byte) error { type row struct { BeginsAt string `json:"begins_at"` Time string `json:"time"` Timestamp string `json:"timestamp"` Value any `json:"value"` Upper any `json:"upper"` Lower any `json:"lower"` MACD any `json:"macd"` Signal any `json:"signal"` } rows, _, err := wire.UnmarshalRows[row](b, "data_points", "points", "results", "values") if err != nil { return err } r.Points = make([]IndicatorPoint, 0, len(rows)) for _, row := range rows { s := row.BeginsAt if s == "" { s = row.Time } if s == "" { s = row.Timestamp } ts, err := time.Parse(time.RFC3339, s) if err != nil { continue } val, err := firstDec(row.Value) if err != nil { return err } up, err := firstDec(row.Upper) if err != nil { return err } lo, err := firstDec(row.Lower) if err != nil { return err } macd, err := firstDec(row.MACD) if err != nil { return err } sig, err := firstDec(row.Signal) if err != nil { return err } r.Points = append(r.Points, IndicatorPoint{Time: ts, Value: val, Upper: up, Lower: lo, MACD: macd, Signal: sig}) } return nil } func (r *NewsResult) UnmarshalJSON(b []byte) error { type row struct { Title string `json:"title"` URL string `json:"url"` PublishedAt string `json:"published_at"` Source string `json:"source"` Summary string `json:"summary"` } rows, next, err := wire.UnmarshalRows[row](b, "news", "articles", "results") if err != nil { return err } r.NextCursor = next r.Articles = make([]NewsArticle, 0, len(rows)) for _, row := range rows { r.Articles = append(r.Articles, NewsArticle{ Title: row.Title, URL: row.URL, PublishedAt: row.PublishedAt, Source: row.Source, Summary: row.Summary, }) } return nil }