equity: Accept open_price aliases in historicals
CI / Test and build (pull_request) Successful in 16s

Live Agentic get_equity_historicals returns
data.results[].bars[] with open_price/high_price/low_price/close_price.
parseHistoricals only read historicals[].data_points[] with short OHLC
names, so CT113 saw bars_len=30 on the wire but 0 parsed bars and VWAP
stayed 0 all day (insufficient_data mass skip).

Accept results|historicals envelopes, bars|data_points arrays, and
*_price aliases alongside short names. Fixture uses the live shape;
legacy short-name envelope stays covered.

Link: #18
This commit is contained in:
ash
2026-09-09 10:07:23 +00:00
parent 51e1539124
commit 27ca0a97c4
2 changed files with 48 additions and 14 deletions
+19 -10
View File
@@ -594,9 +594,13 @@ func appendQuotes(dst []Quote, rows []quoteRow) ([]Quote, error) {
type histPointJSON struct {
BeginsAt string `json:"begins_at"`
Open any `json:"open"`
OpenPrice any `json:"open_price"`
High any `json:"high"`
HighPrice any `json:"high_price"`
Low any `json:"low"`
LowPrice any `json:"low_price"`
Close any `json:"close"`
ClosePrice any `json:"close_price"`
Volume any `json:"volume"`
Interpolated bool `json:"interpolated"`
}
@@ -604,38 +608,43 @@ type histPointJSON struct {
type histSeriesJSON struct {
Symbol string `json:"symbol"`
DataPoints []histPointJSON `json:"data_points"`
Bars []histPointJSON `json:"bars"`
}
func parseHistoricals(raw json.RawMessage) ([]Bar, error) {
var wrap struct {
Historicals []histSeriesJSON `json:"historicals"`
}
if err := json.Unmarshal(wire.Unwrap(raw), &wrap); err != nil {
// Live Agentic wire (CT113): {"data":{"results":[{"symbol","bars":[{open_price,...}]}]}}.
// Fixture / older shapes: {"historicals":[{"symbol","data_points":[{open,...}]}]}.
rows, _, err := wire.UnmarshalRows[histSeriesJSON](raw, "results", "historicals")
if err != nil {
return nil, err
}
var out []Bar
for _, series := range wrap.Historicals {
for _, series := range rows {
if series.Symbol == "" {
continue
}
for _, p := range series.DataPoints {
points := series.Bars
if len(points) == 0 {
points = series.DataPoints
}
for _, p := range points {
ts, err := time.Parse(time.RFC3339, p.BeginsAt)
if err != nil {
continue
}
o, err := firstDec(p.Open)
o, err := firstDec(p.OpenPrice, p.Open)
if err != nil {
return nil, err
}
h, err := firstDec(p.High)
h, err := firstDec(p.HighPrice, p.High)
if err != nil {
return nil, err
}
l, err := firstDec(p.Low)
l, err := firstDec(p.LowPrice, p.Low)
if err != nil {
return nil, err
}
cl, err := firstDec(p.Close)
cl, err := firstDec(p.ClosePrice, p.Close)
if err != nil {
return nil, err
}