Go는 금융 도구로 점점 더 인기가 높습니다. 빠른 컴파일, 예측 가능한 성능 및 일류 동시 원시성은 데이터 파이프 라인 및 거래 자동화에 자연스럽게 적합합니다. 이 가이드는 간단한 일회 요청에서 타임 아웃, JSON 디코딩 및 옵션 날짜 필터링을 처리하는 재사용 클라이언트까지 Go에서 FXMacroData REST API를 호출하는 데 필요한 모든 것을 안내합니다. 결국에는 매크로 지표 발표를 가져와 다가오는 릴리스 캘린더를 당기고 FX 스팟 요금을 150 줄 미만으로 문의하는 구사적인 Go 코드가있을 것입니다.
당신 이 건축 할 것
가벼운 Go HTTP 클라이언트, 질의 매개 변수 API 키 auth를 사용하여 FXMacroData REST API에 대한 인증, 입력된 Go 구조로 구조화된 JSON 응답을 디코드하고, 가장 일반적인 세 가지 엔드포인트 가족: 발표, 릴리스 캘린더 및 FX 스팟 비율에 대한 재사용 가능한 보조 기능을 노출합니다.
필수 조건
No third-party HTTP or JSON libraries are needed — the standard net/http 그리고
encoding/json 패키지가 모든 걸 처리합니다.
단계 1 API 형태를 이해
모든 FXMacroData 지표의 최종 지점은 동일한 URL 패턴을 따르고 있습니다.
GET https://fxmacrodata.com/api/v1/announcements/{currency}/{indicator}?api_key=YOUR_API_KEY
응답은 JSON 객체입니다. data 매 요소에는
date 문자열, 숫자 val, 그리고 선택적으로 announcement_datetime
이 숫자가 공식적으로 공개된 시점에 대한 두 번째 수준의 정확성을 제공합니다. 예를 들어:
curl "https://fxmacrodata.com/api/v1/announcements/usd/wages?api_key=YOUR_API_KEY&start=2024-01-01"
{
"data": [
{ "date": "2025-03-14", "val": 4.0, "announcement_datetime": "2025-03-14T12:30:00Z" },
{ "date": "2025-02-07", "val": 4.1, "announcement_datetime": "2025-02-07T13:30:00Z" },
{ "date": "2025-01-10", "val": 3.9, "announcement_datetime": "2025-01-10T13:30:00Z" }
]
}
같은 프 구조는 달력 및 외환 엔드 포인트에 적용되며, 하나의 일반 디코더를 작성하고 그 위에 엔드 포인트 유형을 전문화하는 것이 간단합니다.
단계 2 모듈을 초기화
프로젝트의 새로운 디렉토리를 만들고 Go 모듈을 초기화합니다:
mkdir fxmd-go && cd fxmd-go
go mod init fxmd
하드 코딩 대신 환경 변수에 API 키를 저장합니다. 현재 셸 세션에 내보낼 수 있습니다:
export FXMD_API_KEY="your_actual_api_key_here"
보안 팁
소스 파일에서 하드 코드 API 키를 절대 사용하지 않거나 버전 제어에 의뢰하지 마십시오. 생산에서는 비밀 관리자 또는 CI / CD 환경 변수를 사용하십시오. 여기 표시된 패턴은 시작 시 키를 읽으며 변수가 없으면 빠르게 실패합니다.
단계 3 반응 유형을 정의
이름의 파일을 만들자 fxmd.go. 당신이 사용할 세 개의 엔드포인트 가족에 의해 반환 된 JSON 모양에 지도를 하는 Go 구조를 정의하여 시작:
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"time"
)
const baseURL = "https://fxmacrodata.com/api/v1"
// DataPoint represents a single indicator observation.
type DataPoint struct {
Date string `json:"date"`
Val float64 `json:"val"`
AnnouncementDatetime string `json:"announcement_datetime,omitempty"`
}
// AnnouncementsResponse is the envelope for indicator announcement endpoints.
type AnnouncementsResponse struct {
Data []DataPoint `json:"data"`
}
// CalendarEvent represents one upcoming or recent release on the calendar.
type CalendarEvent struct {
Date string `json:"date"`
Indicator string `json:"indicator"`
Expected float64 `json:"expected,omitempty"`
Prior float64 `json:"prior,omitempty"`
Actual float64 `json:"actual,omitempty"`
}
// CalendarResponse is the envelope for the release calendar endpoint.
type CalendarResponse struct {
Data []CalendarEvent `json:"data"`
}
// ForexPoint represents a single FX spot-rate observation.
type ForexPoint struct {
Date string `json:"date"`
Rate float64 `json:"rate"`
}
// ForexResponse is the envelope for the FX spot-rate endpoint.
type ForexResponse struct {
Data []ForexPoint `json:"data"`
}
단계 4 재사용 가능한 클라이언트를 구축
얇은 뚜을 싸고 net/http 호출 코드에서 보일러플레트를 제외합니다. 클라이언트는 API 키를 구축 시 한 번 읽고, 모든 요청에 질의 매개 변수로 주입하고, 타임아웃을 강제합니다.
// Client is a lightweight FXMacroData API client.
type Client struct {
apiKey string
httpClient *http.Client
}
// NewClient creates a Client that reads the API key from the FXMD_API_KEY environment variable.
// It panics at startup if the variable is not set — fail-fast is safer than silent empty results.
func NewClient() *Client {
key := os.Getenv("FXMD_API_KEY")
if key == "" {
panic("FXMD_API_KEY environment variable is not set")
}
return &Client{
apiKey: key,
httpClient: &http.Client{
Timeout: 15 * time.Second,
},
}
}
// get performs a GET request to the given path with optional query parameters.
// It decodes the JSON body into dest.
func (c *Client) get(path string, params url.Values, dest any) error {
if params == nil {
params = url.Values{}
}
params.Set("api_key", c.apiKey)
u := baseURL + path + "?" + params.Encode()
resp, err := c.httpClient.Get(u)
if err != nil {
return fmt.Errorf("http get %s: %w", path, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("api error %d on %s: %s", resp.StatusCode, path, body)
}
if err := json.NewDecoder(resp.Body).Decode(dest); err != nil {
return fmt.Errorf("json decode %s: %w", path, err)
}
return nil
}
사용 json.NewDecoder 응답체 (바이트 조각으로 먼저 본체를 읽는 대신) 에 대한 구식 접근법입니다. 그것은 HTTP 연결에서 직접 디코딩을 스트리밍하여 큰 유료로 중간 할당을 피합니다.
단계 5 각 엔드포인트 가족에 입력 보조자를 추가
일반제품을 포장해 get 입력된 보조자를 사용하는 방법, 그래서 호출자는 수동으로 경로를 구성하거나 봉투를 해독할 필요가 없습니다.
// GetAnnouncements retrieves indicator announcement data for the given currency and indicator slug.
// start and end are optional date strings in "YYYY-MM-DD" format; pass "" to omit them.
//
// Example: client.GetAnnouncements("usd", "wages", "2024-01-01", "")
// Full indicator catalogue: https://fxmacrodata.com/api-data-docs/usd/wages
func (c *Client) GetAnnouncements(currency, indicator, start, end string) (*AnnouncementsResponse, error) {
params := url.Values{}
if start != "" {
params.Set("start", start)
}
if end != "" {
params.Set("end", end)
}
var out AnnouncementsResponse
err := c.get("/announcements/"+currency+"/"+indicator, params, &out)
return &out, err
}
// GetCalendar retrieves the upcoming release calendar for the given currency code.
//
// Example: client.GetCalendar("usd")
func (c *Client) GetCalendar(currency string) (*CalendarResponse, error) {
var out CalendarResponse
err := c.get("/calendar/"+currency, nil, &out)
return &out, err
}
// GetForex retrieves FX spot-rate history for a currency pair.
// start and end are optional date strings in "YYYY-MM-DD" format.
//
// Example: client.GetForex("eur", "usd", "2024-01-01", "")
func (c *Client) GetForex(base, quote, start, end string) (*ForexResponse, error) {
params := url.Values{}
if start != "" {
params.Set("start", start)
}
if end != "" {
params.Set("end", end)
}
var out ForexResponse
err := c.get("/forex/"+base+"/"+quote, params, &out)
return &out, err
}
단계 6 모든 것을 연결합니다 main
클라이언트와 보조자가 설치되어 있으면 API를 호출하는 것은 간결하고 타입이 안전합니다. main
기능 fxmd.go 이 세 가지의 최종점 가족들을 모두 실행하는
func main() {
client := NewClient()
// --- Announcements: US wages ---
fmt.Println("=== US Wages (last 5 releases) ===")
wages, err := client.GetAnnouncements("usd", "wages", "2024-01-01", "")
if err != nil {
fmt.Println("error:", err)
} else {
for i, pt := range wages.Data {
if i >= 5 {
break
}
fmt.Printf(" %s val=%.2f released=%s\n", pt.Date, pt.Val, pt.AnnouncementDatetime)
}
}
// --- Release calendar: upcoming USD events ---
fmt.Println("\n=== Upcoming USD Releases ===")
cal, err := client.GetCalendar("usd")
if err != nil {
fmt.Println("error:", err)
} else {
for i, ev := range cal.Data {
if i >= 5 {
break
}
fmt.Printf(" %s %s prior=%.2f expected=%.2f\n",
ev.Date, ev.Indicator, ev.Prior, ev.Expected)
}
}
// --- FX spot rates: EUR/USD ---
fmt.Println("\n=== EUR/USD Spot Rate (last 5 days) ===")
fx, err := client.GetForex("eur", "usd", "2025-01-01", "")
if err != nil {
fmt.Println("error:", err)
} else {
for i, pt := range fx.Data {
if i >= 5 {
break
}
fmt.Printf(" %s rate=%.5f\n", pt.Date, pt.Rate)
}
}
}
프로그램을 실행하세요:
go run fxmd.go
아래와 같은 출력을 볼 수 있습니다.
=== US Wages (last 5 releases) ===
2025-03-14 val=4.00 released=2025-03-14T12:30:00Z
2025-02-07 val=4.10 released=2025-02-07T13:30:00Z
2025-01-10 val=3.90 released=2025-01-10T13:30:00Z
2024-12-06 val=4.00 released=2024-12-06T13:30:00Z
2024-11-01 val=4.00 released=2024-11-01T12:30:00Z
=== Upcoming USD Releases ===
2025-04-25 gdp prior=2.30 expected=0.40
2025-05-02 non_farm_payrolls prior=228.00 expected=135.00
2025-05-13 inflation prior=2.40 expected=2.30
=== EUR/USD Spot Rate (last 5 days) ===
2025-04-17 rate=1.13452
2025-04-16 rate=1.13680
2025-04-15 rate=1.13590
2025-04-14 rate=1.13320
2025-04-11 rate=1.13580
팁 로루틴과 함께 동시에 가져오기
클라이언트가 동시에 사용하기에 안전하기 때문에, 당신은 goroutines와 를 사용하여 여러 지표 요청을 병행으로 퍼뜨릴 수 있습니다. sync.WaitGroup 아니면 errgroup이것은 한 번에 여러 통화를 뽑는 대시보드를 만들 때 특히 유용합니다.
단계 7 페이지화 및 날짜 범위를 처리
기본적으로, 발표 엔드포인트는 사용 가능한 모든 역사를 반환합니다.
M2 통화 공급 아니면 국내총생산 당신은 종종 창을 제한하고 싶어 할 것입니다 start 그리고 end 두 보조기 모두 이미 지원합니다. 여기 가장 최근의 분기만 가져오는 집중된 예가 있습니다.
미국 비정규직 데이터:
// Fetch US part-time employment for the last 90 days
end := time.Now().Format("2006-01-02")
start := time.Now().AddDate(0, 0, -90).Format("2006-01-02")
pt, err := client.GetAnnouncements("usd", "part_time_employment", start, end)
if err != nil {
log.Fatal(err)
}
for _, dp := range pt.Data {
fmt.Printf("%s %.0f\n", dp.Date, dp.Val)
}
의 표준 time 패키지 포맷 날짜는 "2006-01-02" ( 참조 시간은 기억기: 01/02 03:04:05 PM '06 -0700), 이는 API가 예상하는 ISO-8601 날짜 문자열과 일치합니다.
단계 8 분석 announcement_datetime time.Time
- announcement_datetime 이 필드는 UTC RFC-3339 문자열입니다. 응용 프로그램이 출시 시간 카운트다운, 이벤트 분류 또는 세션별로 버킷 데이터를 계산해야하는 경우,
time.Time 값:
const rfc3339 = time.RFC3339
for _, dp := range wages.Data {
if dp.AnnouncementDatetime == "" {
continue
}
t, err := time.Parse(rfc3339, dp.AnnouncementDatetime)
if err != nil {
log.Printf("bad datetime %q: %v", dp.AnnouncementDatetime, err)
continue
}
until := time.Until(t)
fmt.Printf("%s val=%.2f in %s\n", dp.Date, dp.Val, until.Round(time.Minute))
}
전체 파일 목록
참고로, 여기 위에 설명 한 단계에 설명 한 전체 단일 파일 구현입니다:
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"time"
)
const baseURL = "https://fxmacrodata.com/api/v1"
type DataPoint struct {
Date string `json:"date"`
Val float64 `json:"val"`
AnnouncementDatetime string `json:"announcement_datetime,omitempty"`
}
type AnnouncementsResponse struct {
Data []DataPoint `json:"data"`
}
type CalendarEvent struct {
Date string `json:"date"`
Indicator string `json:"indicator"`
Expected float64 `json:"expected,omitempty"`
Prior float64 `json:"prior,omitempty"`
Actual float64 `json:"actual,omitempty"`
}
type CalendarResponse struct {
Data []CalendarEvent `json:"data"`
}
type ForexPoint struct {
Date string `json:"date"`
Rate float64 `json:"rate"`
}
type ForexResponse struct {
Data []ForexPoint `json:"data"`
}
type Client struct {
apiKey string
httpClient *http.Client
}
func NewClient() *Client {
key := os.Getenv("FXMD_API_KEY")
if key == "" {
panic("FXMD_API_KEY environment variable is not set")
}
return &Client{
apiKey: key,
httpClient: &http.Client{Timeout: 15 * time.Second},
}
}
func (c *Client) get(path string, params url.Values, dest any) error {
if params == nil {
params = url.Values{}
}
params.Set("api_key", c.apiKey)
u := baseURL + path + "?" + params.Encode()
resp, err := c.httpClient.Get(u)
if err != nil {
return fmt.Errorf("http get %s: %w", path, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("api error %d on %s: %s", resp.StatusCode, path, body)
}
return json.NewDecoder(resp.Body).Decode(dest)
}
func (c *Client) GetAnnouncements(currency, indicator, start, end string) (*AnnouncementsResponse, error) {
params := url.Values{}
if start != "" { params.Set("start", start) }
if end != "" { params.Set("end", end) }
var out AnnouncementsResponse
return &out, c.get("/announcements/"+currency+"/"+indicator, params, &out)
}
func (c *Client) GetCalendar(currency string) (*CalendarResponse, error) {
var out CalendarResponse
return &out, c.get("/calendar/"+currency, nil, &out)
}
func (c *Client) GetForex(base, quote, start, end string) (*ForexResponse, error) {
params := url.Values{}
if start != "" { params.Set("start", start) }
if end != "" { params.Set("end", end) }
var out ForexResponse
return &out, c.get("/forex/"+base+"/"+quote, params, &out)
}
func main() {
client := NewClient()
wages, err := client.GetAnnouncements("usd", "wages", "2024-01-01", "")
if err != nil {
fmt.Println("wages error:", err)
} else {
fmt.Println("=== US Wages ===")
for i, pt := range wages.Data {
if i >= 5 { break }
fmt.Printf(" %s %.2f\n", pt.Date, pt.Val)
}
}
cal, err := client.GetCalendar("usd")
if err != nil {
fmt.Println("calendar error:", err)
} else {
fmt.Println("=== Upcoming USD Releases ===")
for i, ev := range cal.Data {
if i >= 5 { break }
fmt.Printf(" %s %s\n", ev.Date, ev.Indicator)
}
}
fx, err := client.GetForex("eur", "usd", "2025-01-01", "")
if err != nil {
fmt.Println("forex error:", err)
} else {
fmt.Println("=== EUR/USD ===")
for i, pt := range fx.Data {
if i >= 5 { break }
fmt.Printf(" %s %.5f\n", pt.Date, pt.Rate)
}
}
}
다음 단계
이제 가장 일반적인 FXMacroData 엔드포인트 가족을 다루는 작동하는 Go 클라이언트가 있습니다. 몇 가지 자연스러운 다음 단계:
- 구조 정의를 확장 추가적인 필드를 캡처하기 위해
revised달력 최종점으로부터 값 - 더해
errgroup-비팬-아웃 여러 화폐를 동시에 가져오기 위해Client로틴을 공유하는 것이 안전합니다.http.Client설계상 동시에 작동할 수 없습니다. - 로컬 SQLite 데이터베이스에 결과를 계속 전송 사용
database/sql가벼운 백테스팅이나 신호 연구용 - 전체 지표 카탈로그를 살펴보십시오 미국 달러 /api-data-docs/usd/임금 그리고 다른 통화들을 대시보드에서 을 찾아보세요. M2 아르바이트그리고 국내총생산 이 가이드를 동기화 한 수요 신호를 고려하여 출발점으로.