Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
31e7683
feat(macrodata): add country filter, count field, offset param
hogan-yuan Jun 10, 2026
97b68fd
fix: trim MacrodataCountry to 6 supported countries (HK/CN/US/EU/JP/SG)
hogan-yuan Jun 10, 2026
c94a4c0
fix: convert MacrodataCountry code to API full name before request
hogan-yuan Jun 10, 2026
c480822
refactor: rename macrodata -> macroeconomic in all interfaces and types
hogan-yuan Jun 11, 2026
090f4b5
refactor: rename Macrodata (data point type) to Macroeconomic
hogan-yuan Jun 11, 2026
c2a97c9
refactor: rename macrodataCountryToAPIValue to macroeconomicCountryTo…
hogan-yuan Jun 11, 2026
9b6c289
refactor: rename all remaining macrodata -> macroeconomic
hogan-yuan Jun 11, 2026
6d1f600
docs: update CHANGELOG with correct macroeconomic naming
hogan-yuan Jun 11, 2026
db4335c
feat: switch macroeconomic APIs to v2 endpoints
hogan-yuan Jun 12, 2026
bdfddeb
feat: pass offset/limit to v2 and handle total from pagination response
hogan-yuan Jun 12, 2026
7686d4b
fix: update v2 detail response to use indicator (single) instead of i…
hogan-yuan Jun 12, 2026
1a1563d
fix: support both indicator/indicator_data_list response formats; fix…
hogan-yuan Jun 12, 2026
37e8e99
refactor: remove indicator_data_list compatibility, use indicator only
hogan-yuan Jun 12, 2026
50c150b
feat: add periodicity/description/importance to v2 MacroeconomicIndic…
hogan-yuan Jun 12, 2026
62e11ac
fix: use frequence (not periodicity) as field name from v2 proto
hogan-yuan Jun 12, 2026
490986a
refactor: change MacroeconomicIndicator.Name/Describe from MultiLangu…
hogan-yuan Jun 12, 2026
0cd877e
refactor: change Macroeconomic.Unit/UnitPrefix from MultiLanguageText…
hogan-yuan Jun 12, 2026
4247332
refactor: remove unused helper functions
hogan-yuan Jun 12, 2026
61abd16
feat: default sort to desc in MacroeconomicV2
hogan-yuan Jun 12, 2026
ff12e4d
feat: add keyword param to MacroeconomicIndicators; hide _v2 variants
hogan-yuan Jun 12, 2026
f3385e1
chore: add v0.26.0 CHANGELOG entry for macroeconomic v2 changes
hogan-yuan Jun 12, 2026
9b3c080
chore: rename v0.26.0 to v0.25.1 in CHANGELOG
hogan-yuan Jun 12, 2026
094b620
merge: bring feat/macrodata-v2 changes into feat/macroeconomic-v2
hogan-yuan Jun 12, 2026
fbe9598
docs: update v0.25.1 CHANGELOG content
hogan-yuan Jun 12, 2026
abdfd57
feat(macroeconomic): switch to v2 endpoints
hogan-yuan Jun 12, 2026
7d197b3
fix(macroeconomic): align v2 request params and count fallback with R…
hogan-yuan Jun 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## [v0.25.1] - 2026-06-13

### Added

- **All languages:** `macroeconomic_indicators` gains `keyword` parameter for fuzzy name filtering
- **All languages:** `macroeconomic` switches to `GET /v2/quote/macrodata/{id}`, defaults to `sort=desc`

### Changed

- `MacroeconomicIndicator.name` / `.describe`: `MultiLanguageText` → `string`
- `Macroeconomic.unit` / `.unit_prefix`: `MultiLanguageText` → `string`

## [v0.25.0] - 2026-06-10

### Added
Expand Down
127 changes: 58 additions & 69 deletions fundamental/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -1616,43 +1616,52 @@ func convertFinancialReportSnapshot(j *jsontypes.FinancialReportSnapshot) *Finan

// MacroeconomicIndicators fetches the list of available macroeconomic indicators.
//
// Pass country to filter by country code (e.g. MacroeconomicCountryUS).
// Pass nil for all countries.
// Pass country to filter by country code (e.g. MacroeconomicCountryUS); nil for all.
// Pass keyword for fuzzy name filtering; nil for no filter.
//
// Path: GET /v1/quote/macrodata
// Path: GET /v2/quote/macrodata
func (c *FundamentalContext) MacroeconomicIndicators(
ctx context.Context,
country *MacroeconomicCountry,
keyword *string,
offset *int32,
limit *int32,
) (*MacroeconomicIndicatorListResponse, error) {
q := url.Values{}
if country != nil {
q.Set("country", macroeconomicCountryToAPIValue(*country))
q.Set("market", string(*country))
}
if keyword != nil {
q.Set("keyword", *keyword)
}
if offset != nil {
q.Set("offset", fmt.Sprintf("%d", *offset))
}
if limit != nil {
q.Set("limit", fmt.Sprintf("%d", *limit))
}
var resp jsontypes.MacroeconomicIndicatorListResponse
if err := c.httpClient.Get(ctx, "/v1/quote/macrodata", q, &resp); err != nil {
var resp jsontypes.V2MacroeconomicIndicatorListResponse
if err := c.httpClient.Get(ctx, "/v2/quote/macrodata", q, &resp); err != nil {
return nil, err
}
out := make([]MacroeconomicIndicator, 0, len(resp.Data))
for _, item := range resp.Data {
out = append(out, convertMacroeconomicIndicator(&item))
out := make([]MacroeconomicIndicator, 0, len(resp.IndicatorList))
for _, item := range resp.IndicatorList {
out = append(out, convertV2MacroeconomicIndicator(&item))
}
count := resp.Total
if count == 0 {
count = int32(len(out))
}
return &MacroeconomicIndicatorListResponse{Data: out, Count: resp.Count}, nil
return &MacroeconomicIndicatorListResponse{Data: out, Count: count}, nil
}

// Macroeconomic fetches historical data for a specific macroeconomic indicator.
//
// indicatorCode is the IndicatorCode returned by MacroeconomicIndicators.
// startDate and endDate are date strings in "YYYY-MM-DD" format.
// startDate is sent as YYYY-MM-DDT00:00:00Z; endDate is sent as YYYY-MM-DDT23:59:59Z.
// Results are sorted descending (newest first) by default.
//
// Path: GET /v1/quote/macrodata/{indicator_code}
// Path: GET /v2/quote/macrodata/{indicator_id}
func (c *FundamentalContext) Macroeconomic(
ctx context.Context,
indicatorCode string,
Expand All @@ -1662,42 +1671,39 @@ func (c *FundamentalContext) Macroeconomic(
limit *int32,
) (*MacroeconomicResponse, error) {
q := url.Values{}
q.Set("sort", "desc")
if startDate != nil {
q.Set("start_time", *startDate+"T00:00:00Z")
q.Set("start_date", *startDate)
}
if endDate != nil {
q.Set("end_time", *endDate+"T23:59:59Z")
q.Set("end_date", *endDate)
}
if offset != nil {
q.Set("offset", fmt.Sprintf("%d", *offset))
}
if limit != nil {
q.Set("limit", fmt.Sprintf("%d", *limit))
}
var resp jsontypes.MacroeconomicResponse
path := "/v1/quote/macrodata/" + indicatorCode
var resp jsontypes.V2MacroeconomicResponse
path := "/v2/quote/macrodata/" + indicatorCode
if err := c.httpClient.Get(ctx, path, q, &resp); err != nil {
return nil, err
}
data := make([]Macroeconomic, 0, len(resp.Data))
for _, d := range resp.Data {
data = append(data, convertMacroeconomic(&d))
data := make([]Macroeconomic, 0, len(resp.Indicator.IndicatorData))
for _, d := range resp.Indicator.IndicatorData {
data = append(data, convertV2Macroeconomic(&d, resp.Indicator.Unit))
}
count := resp.Total
if count == 0 {
count = int32(len(data))
}
return &MacroeconomicResponse{
Info: convertMacroeconomicIndicator(&resp.Info),
Info: convertV2MacroeconomicDetail(&resp.Indicator),
Data: data,
Count: resp.Count,
Count: count,
}, nil
}

func convertMultiLanguageText(j jsontypes.MultiLanguageText) MultiLanguageText {
return MultiLanguageText{
English: j.English,
SimplifiedChinese: j.SimplifiedChinese,
TraditionalChinese: j.TraditionalChinese,
}
}

func parseOptionalRFC3339(s string) *time.Time {
if s == "" {
return nil
Expand All @@ -1710,50 +1716,33 @@ func parseOptionalRFC3339(s string) *time.Time {
return &t
}

func convertMacroeconomicIndicator(j *jsontypes.MacroeconomicIndicator) MacroeconomicIndicator {
func convertV2MacroeconomicIndicator(j *jsontypes.V2MacroeconomicIndicator) MacroeconomicIndicator {
return MacroeconomicIndicator{
IndicatorCode: j.IndicatorCode,
SourceOrg: j.SourceOrg,
Country: j.Country,
Name: convertMultiLanguageText(j.Name),
AdjustmentFactor: j.AdjustmentFactor,
Periodicity: j.Periodicity,
Category: j.Category,
Describe: convertMultiLanguageText(j.Describe),
Importance: j.Importance,
StartDate: parseOptionalRFC3339(j.StartDate),
IndicatorCode: strconv.FormatInt(int64(j.IndicatorID), 10),
Country: j.Market,
Name: j.IndicatorName,
Describe: j.Description,
Importance: j.Importance,
Periodicity: j.Frequence,
}
}

func convertMacroeconomic(j *jsontypes.Macroeconomic) Macroeconomic {
func convertV2MacroeconomicDetail(j *jsontypes.V2MacroeconomicDetail) MacroeconomicIndicator {
return MacroeconomicIndicator{
IndicatorCode: strconv.FormatInt(int64(j.IndicatorID), 10),
Country: j.Market,
Name: j.IndicatorName,
Describe: j.Description,
}
}

func convertV2Macroeconomic(j *jsontypes.V2IndicatorDataDetail, unit string) Macroeconomic {
return Macroeconomic{
Period: j.Period,
ReleaseAt: parseOptionalRFC3339(j.ReleaseAt),
ActualValue: j.ActualValue,
PreviousValue: j.PreviousValue,
ForecastValue: j.ForecastValue,
RevisedValue: j.RevisedValue,
NextReleaseAt: parseOptionalRFC3339(j.NextReleaseAt),
Unit: convertMultiLanguageText(j.Unit),
UnitPrefix: convertMultiLanguageText(j.UnitPrefix),
}
}

func macroeconomicCountryToAPIValue(c MacroeconomicCountry) string {
switch c {
case MacroeconomicCountryHK:
return "Hong Kong SAR China"
case MacroeconomicCountryCN:
return "China (Mainland)"
case MacroeconomicCountryUS:
return "United States"
case MacroeconomicCountryEU:
return "Euro Zone"
case MacroeconomicCountryJP:
return "Japan"
case MacroeconomicCountrySG:
return "Singapore"
default:
return string(c)
Period: j.ObservationDate,
ReleaseAt: parseOptionalRFC3339(j.PublishedTime),
ActualValue: j.ActualData,
PreviousValue: j.PreviousData,
ForecastValue: j.EstimatedData,
Unit: unit,
}
}
46 changes: 45 additions & 1 deletion fundamental/jsontypes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -845,5 +845,49 @@ type Macroeconomic struct {
type MacroeconomicResponse struct {
Info MacroeconomicIndicator `json:"info"`
Data []Macroeconomic `json:"data"`
Count int32 `json:"count"`
Count int32 `json:"count"`
}

// ── v2 wire types ─────────────────────────────────────────────────

// V2MacroeconomicIndicator is one indicator from GET /v2/quote/macrodata.
type V2MacroeconomicIndicator struct {
IndicatorID int32 `json:"indicator_id"`
IndicatorName string `json:"indicator_name"`
Market string `json:"market"`
Importance int32 `json:"importance"`
Description string `json:"description"`
// Frequence: day/week/month/quarter/half_year/year
Frequence string `json:"frequence"`
}

// V2MacroeconomicIndicatorListResponse is the response for GET /v2/quote/macrodata.
type V2MacroeconomicIndicatorListResponse struct {
IndicatorList []V2MacroeconomicIndicator `json:"indicator_list"`
Total int32 `json:"total"`
}

// V2IndicatorDataDetail is one data point from GET /v2/quote/macrodata/:id.
type V2IndicatorDataDetail struct {
ActualData string `json:"actual_data"`
PreviousData string `json:"previous_data"`
EstimatedData string `json:"estimated_data"`
PublishedTime string `json:"published_time"`
ObservationDate string `json:"observation_date"`
}

// V2MacroeconomicDetail is one indicator with data from GET /v2/quote/macrodata/:id.
type V2MacroeconomicDetail struct {
IndicatorID int32 `json:"indicator_id"`
IndicatorName string `json:"indicator_name"`
Unit string `json:"unit"`
Description string `json:"description"`
Market string `json:"market"`
IndicatorData []V2IndicatorDataDetail `json:"indicator_data"`
}

// V2MacroeconomicResponse is the response for GET /v2/quote/macrodata/:id (GetMacroIndicatorHistoryResp).
type V2MacroeconomicResponse struct {
Indicator V2MacroeconomicDetail `json:"indicator"`
Total int32 `json:"total"`
}
8 changes: 4 additions & 4 deletions fundamental/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1398,12 +1398,12 @@ type MacroeconomicIndicator struct {
IndicatorCode string
SourceOrg string
Country string
Name MultiLanguageText
Name string
AdjustmentFactor string
// Periodicity is the release periodicity (e.g. monthly / quarterly).
Periodicity string
Category string
Describe MultiLanguageText
Describe string
// Importance: 1=Low, 2=Medium, 3=High.
Importance int32
// StartDate is the start date of data coverage; nil if unset.
Expand All @@ -1420,8 +1420,8 @@ type Macroeconomic struct {
ForecastValue string
RevisedValue string
NextReleaseAt *time.Time
Unit MultiLanguageText
UnitPrefix MultiLanguageText
Unit string
UnitPrefix string
}

// MacroeconomicResponse is the response for FundamentalContext.Macroeconomic.
Expand Down