Goは金融ツールとしてますます人気がある. 迅速なコンパイル,予測可能なパフォーマンス,一流の並行プリミティブにより,データパイプラインと取引自動化に自然に適している. このガイドでは,簡単な一次要求からタイムアウト,JSON解読,オプション日付フィルタリングを処理する再利用可能なクライアントまで,GoからFXMacroData REST APIを呼び出すために必要なすべてのことを説明します. 終了までに,マクロインジケーターの発表を取得し,即日リリースカレンダーを引っ張り,FXスポットレートを検索するアイディアマティックGoコードが150行未満で表示されます.
あなた が 築く もの
A lightweight Go HTTP client that authenticates against the FXMacroData REST API using query-parameter API-key auth, decodes structured JSON responses into typed Go structs, and exposes reusable helper functions for the three most common endpoint families: announcements, release calendar, and FX spot rates.
条件
- Go 1.21 以降のバージョンがインストールされている (go.dev/dl について) について
- 登録する / サブスクリプト 受け取る
- Go モジュールと標準ライブラリとの基本的な熟知
標準は第三者のHTTPやJSONライブラリを必要としません. net/http ほら
encoding/json パッケージが全て処理する
Step 1 — Understand the API Shape
FXMacroDataのすべてのエンドポイントは同じURLパターンをフォローします.
GET https://fxmacrodata.com/api/v1/announcements/{currency}/{indicator}?api_key=YOUR_API_KEY
応答はJSONオブジェクトで,上位レベルです. data 配列.各要素には
date 文字列,数値 val選択可能な announcement_datetime
that gives second-level precision for when the figure was officially released. For example:
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. Start by defining the Go structs that map to the JSON
shapes returned by the three endpoint families you will use:
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 応答ボディ (最初にボディをバイトスライスに読み込むのではなく) に Go の慣用語アプローチがあります. 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 that exercises all three endpoint families:
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
ゲロータインと同時取材
複数のインディケーターリクエストを並行して 広げることができます sync.WaitGroup ほら errgroupウォールクロック時間は,すべてのリクエストの合計よりも,最も遅い単一のリクエールの遅延に近い.
ステップ7 ページ付けと日付範囲を処理する
長期間のシリーズでは, 終了時に表示されるすべての情報が返されます.
M2 money supply ほら GDP 窓を制限したい場合もあります 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)
}
}
}
次は?
You now have a working Go client that covers the three most common FXMacroData endpoint families. A few natural next steps:
- 構造の定義を拡張する 追加フィールドを記録する
revised暦の最終点から値 - 追加する
errgroupファンアウト 複数の通貨を同時に取得するClientゲロートインで共有するのは安全ですhttp.Client設計上は同時動作を防ぎます - ローカル SQLite データベースへの結果の持続 薬剤を
database/sql軽量なバックテストや信号研究のために - 指標のカタログをすべて調べる ドルに対して /api-data-docs/USD/賃金 労働者は,労働者に ダイッシュボードの他の通貨では を検索します M2ほら 副業ほら GDP このガイドを動機とした需要信号から始めます