# Getting Started With The Golang Stock API

> Get financial data in Go using the Golang Stock API. The SDK includes a variety of methods for accessing financial data such as real-time stock quotes.

Source: https://www.marketdata.app/sdk/go/golang-stock-api/

---

(image: The Go language GO wordmark with trailing speed lines, glowing white against a purple starfield.)

-   [Go SDK](/topics/sdk/go/)
-   [Stock Data](/topics/data/stocks/)
-   [Tutorials](/tutorials/)

Get financial data in Go using the Golang Stock API. The SDK includes a variety of methods for accessing financial data such as real-time stock quotes.

-   Last updated September 4, 2026

Although stock data APIs are becoming more commonplace, it is rare to find one that supports Go. This is why Market Data set out to build our own Golang Stock API with a focus on rapid development and ease of use. Our Go SDK’s API has [extensive documentation](/docs/sdk/go), examples for every endpoint, and is easy to get up and running.

This tutorial takes you from an empty directory to a printed stock quote. It is a handful of commands and about twenty lines of Go.

## Setting Up Your Environment

To set up your environment for using the Market Data Go SDK, follow these steps:

1.  **Sign Up for a Market Data Account**: Visit Market Data to sign up for a free account. This account gives you access to the API, allowing you to explore its capabilities without any cost. You can also opt for a paid plan with a 30-day free trial to explore premium features.
2.  **Set Up Authentication**: After signing up, you’ll receive an API token via email. Set this token as an environment variable named `MARKETDATA_TOKEN` to authenticate your requests to the Market Data API. This can be done in your terminal:
    -   For macOS/Linux: `export MARKETDATA_TOKEN="<your_api_token>"`
    -   For Windows: `setx MARKETDATA_TOKEN "<your_api_token>"`
3.  **Install the SDK**: Use the Go package manager to install the SDK. The `/v2` is part of the module path itself, so it appears in the `go get` command and in every import:
    `go get github.com/MarketDataApp/sdk-go/v2`
4.  **Import the SDK in Your Project**: The client lives in the `marketdata` package, and each group of endpoints has a package of its own beside it:
    `import "github.com/MarketDataApp/sdk-go/v2/marketdata"`

From an empty directory, that is three commands:

```
mkdir quote-demo && cd quote-demo
go mod init quote-demo
go get github.com/MarketDataApp/sdk-go/v2
```

The SDK requires **Go 1.22 or later**, and it pulls in no third-party dependencies: everything it needs at runtime is in the Go standard library.

## Fetching a Real-Time Stock Quote With The Golang Stock API

If you’ve used our API before, you’re probably already familiar with [getting live stock quotes](/api/stocks/stock-market-api/) from our [stock quote endpoint](/docs/api/stocks/quotes). Using the Go SDK is just as easy. Save this as `main.go` in the directory you just created:

```
package main

import (
  "context"
  "fmt"
  "log"

  "github.com/MarketDataApp/sdk-go/v2/marketdata"
)

func main() {
  // NewClient reads MARKETDATA_TOKEN from the environment or a .env file.
  client, err := marketdata.NewClient()
  if err != nil {
    log.Fatalf("Failed to create the client: %v", err)
  }
  defer client.Close()

  ctx := context.Background()

  // Every method takes a context first and returns three values: the data,
  // the response metadata, and an error.
  quote, resp, err := client.Stocks.Quote(ctx, "AAPL")
  if err != nil {
    log.Fatalf("Failed to get the stock quote: %v", err)
  }

  // A quote describes a single thing, so the SDK returns a nil pointer when
  // the API had no data. Check it before you read a field.
  if quote == nil {
    log.Fatal("No quote data was available for AAPL.")
  }

  fmt.Println(quote)
  fmt.Printf("Credits remaining: %d\n", resp.RateLimit.Remaining)
}
```

Run it with `go run .`, and put your own symbol in place of AAPL. Two things in that program are worth naming, because every other call you make will have the same shape.

The **middle return value** is the response metadata. It carries the rate-limit headers for that exact request, a `NoData` flag, and the raw `*http.Response`. Discard it with `_` whenever you do not need it.

The **`fmt.Println(quote)`** works because every response type implements `fmt.Stringer`. You get a readable one-line summary without writing a format string:

```
AAPL Last: $302.77 Bid: 302.75 (2) Ask: 302.79 (3) Mid: 302.77 Chg: -0.65 (-0.21%) Vol: 41203110 Updated: 2026-08-04 10:15:04
```

The snippets in the rest of this tutorial assume the `client` and the `ctx` from that program.

### Two Ways to Call Every Endpoint

Every method comes in two forms. The context-first form above is the one to use in a real program. Beside it is a `Get`\-prefixed convenience wrapper that supplies a background context and returns only the data and the error:

```
quote, err := client.Stocks.GetQuote("AAPL")
if err != nil {
  log.Fatalf("Failed to get the stock quote: %v", err)
}
fmt.Println(quote)
```

Use `GetQuote` for a script or a quick experiment. Use `Quote` when you want a deadline, cancellation, or the rate-limit numbers.

### Fetching Many Symbols At Once

The plural method takes a slice, and the whole set costs one API request:

```
quotes, _, err := client.Stocks.Quotes(ctx, []string{"AAPL", "MSFT", "GOOG"})
if err != nil {
  log.Fatalf("Failed to get the stock quotes: %v", err)
}

for _, q := range quotes {
  fmt.Printf("%s: $%.2f (%.2f%%)\n", q.Symbol, q.Last, q.ChangePercent*100)
}
```

## Working with Stock Quotes in Go

Understanding the stock data returned by the Go SDK involves getting familiar with the [Quote struct](/docs/sdk/go/stocks/quote/#quote-1), which is central to handling stock data in the Market Data Go SDK. It lives in the `stocks` package, so you will see it written as `stocks.Quote`, and it encapsulates the details of a full level 1 stock quote.

```
type Quote struct {
    Symbol           string    // Symbol is the stock ticker symbol.
    Ask              float64   // Ask is the current ask price.
    AskSize          int       // AskSize is the size of the ask.
    Bid              float64   // Bid is the current bid price.
    BidSize          int       // BidSize is the size of the bid.
    Mid              float64   // Mid is the midpoint between bid and ask.
    Last             float64   // Last is the last trade price.
    Change           float64   // Change is the price change from the previous close.
    ChangePercent    float64   // ChangePercent is the FRACTIONAL change: -0.0021 means -0.21%.
    Volume           int64     // Volume is the trading volume.
    Updated          time.Time // Updated is when the quote was last updated, in US/Eastern.
    FiftyTwoWeekHigh float64   // Requested with stocks.WithFiftyTwoWeek(true).
    FiftyTwoWeekLow  float64   // Requested with stocks.WithFiftyTwoWeek(true).
    Open             float64   // Session OHLC, requested with stocks.WithCandle(true).
    High             float64
    Low              float64
    Close            float64
}
```

### Interpreting the Quote Struct

When interpreting the data fields, it’s important to consider the context of the stock market and the specific stock you’re analyzing. For example, a significant change in the **Ask** and **Bid** prices could indicate a shift in market sentiment, while the **Volume** can give insights into the stock’s liquidity. The **FiftyTwoWeekHigh** and **FiftyTwoWeekLow** provide a perspective on the stock’s performance over the past year, and the **Change** and **ChangePercent** offer immediate feedback on recent price movements.

Two details of the struct will catch you out if you skip them:

-   **`ChangePercent` is a fraction, not a percentage.** The API sends `-0.0021` to mean −0.21%, and the SDK passes it through unchanged. Multiply by 100 before you print it. The `String()` method already does this for you.
-   **The 52-week fields are empty unless you ask for them.** They stay at zero unless the request carried `stocks.WithFiftyTwoWeek(true)`, and that option exists only on the single-symbol `Quote` method — the bulk quotes endpoint does not supply the data.

Every timestamp the SDK returns is normalized to US/Eastern, the timezone of the US exchanges, so you do not have to convert `Updated` before comparing it to a market session.

The struct also carries two helper methods, so you do not have to work the arithmetic out yourself:

```
fmt.Printf("Spread: %.2f (%.2f%% of the mid)\n", quote.Spread(), quote.SpreadPercent())
```

To fetch the 52-week range, pass the option:

```
quote, _, err := client.Stocks.Quote(ctx, "AAPL", stocks.WithFiftyTwoWeek(true))
if err != nil {
  log.Fatalf("Failed to get the stock quote: %v", err)
}
if quote != nil {
  fmt.Printf("52-week range: %.2f - %.2f\n", quote.FiftyTwoWeekLow, quote.FiftyTwoWeekHigh)
}
```

That option comes from the `stocks` package, so add it to your imports when you use one:

```
import "github.com/MarketDataApp/sdk-go/v2/marketdata/stocks"
```

## Handling Errors and Missing Data

The SDK returns typed errors that work with `errors.Is` and `errors.As`, and it separates two situations that both arrive from the API as an HTTP 404.

A **symbol the API does not recognize** is an error, so a typo fails loudly instead of reading as an empty answer:

```
quote, resp, err := client.Stocks.Quote(ctx, "ZZZZQQ")
if err != nil {
  if errors.Is(err, marketdata.ErrNotFound) {
    log.Fatal("That symbol does not exist.")
  }

  // Errors the API produced carry a support block you can paste into a ticket.
  var apiErr *marketdata.APIError
  if errors.As(err, &apiErr) {
    log.Fatal(apiErr.SupportInfo())
  }

  log.Fatalf("Failed to get the stock quote: %v", err)
}
```

A **valid question with an empty answer** is not an error. The error is nil, `resp.NoData` is true, and the result is empty rather than absent. Methods that return a slice give you an empty slice, which is safe to range over. `Quote` returns a nil pointer, because a zero-valued quote would read as a real price of zero:

```
if quote == nil {
  fmt.Println("The request succeeded, but the API had no quote to return.")
  fmt.Println("NoData:", resp.NoData)
}
```

Rate limiting has a sentinel of its own, so you can back off rather than retry blindly:

```
if errors.Is(err, marketdata.ErrRateLimited) {
  fmt.Println("Out of credits for now.")
}
```

Two numbers tell you where you stand. `resp.RateLimit` is exact and describes the request you just made; `client.RateLimits()` is a running snapshot of the last completed response, which is convenient for monitoring but may lag when requests run concurrently.

```
limits := client.RateLimits()
fmt.Printf("Credits: %d of %d remaining, resets at %v\n",
  limits.Remaining, limits.Limit, limits.ResetAt)
```

## Configuring the Client

`NewClient` needs no arguments, because it reads `MARKETDATA_TOKEN` from the environment. It also reads a `.env` file in your working directory, and a real environment variable always wins over the file.

To pass the token yourself, or to change any other setting, use the functional options:

```
client, err := marketdata.NewClient(
  marketdata.WithToken("<your_api_token>"),
  marketdata.WithMaxRetries(3),
  marketdata.WithDebug(true),
)
if err != nil {
  log.Fatalf("Failed to create the client: %v", err)
}
defer client.Close()
```

Create one client and pass it around: it is safe to share across goroutines, and it limits itself to 50 requests in flight at a time. Give it a `defer client.Close()` so it releases its resources when your program ends.

## Going Further: Historical Candles

Quotes are one endpoint of many, and the rest follow the same shape. Historical candles show the other half of the design — optional parameters arrive as functional options:

```
candles, _, err := client.Stocks.Candles(ctx, "AAPL",
  stocks.WithResolution(stocks.ResolutionDaily),
  stocks.WithCandleWindow(stocks.LastN(30)),
)
if err != nil {
  log.Fatalf("Failed to get the candles: %v", err)
}

for _, c := range candles {
  fmt.Println(c)
}
```

`WithCandleWindow` takes one value that describes the whole date range, built from a `time.Time`. `LastN(30)` asks for the 30 most recent periods; `Between(from, to)`, `Since(from)`, `Until(to)`, `OnDate(day)` and `LastNUntil(n, to)` are the other ways to say it.

The window being a single value is deliberate. The API’s date parameters are mutually exclusive, and that exclusivity is enforced by the compiler: a date range plus a countback is not something you can write. An illegal combination fails to build rather than failing at runtime with a message from the server.

Beyond stocks, the client groups the rest of the API into `client.Options`, `client.Funds`, `client.Markets` and `client.Utilities`. They all work the way the calls above do.

## Additional Resources

You can consult the [Market Data Go SDK on Github](https://github.com/MarketDataApp/sdk-go) as well as access the [SDK’s documentation on pkg.go.dev](https://pkg.go.dev/github.com/MarketDataApp/sdk-go/v2). The repository also ships [runnable examples](https://github.com/MarketDataApp/sdk-go/tree/main/examples), from a copy-paste quick start to full-screen terminal apps that between them exercise every SDK method. However, we recommend using our own [Go SDK Documentation Portal](/docs/sdk/go) for detailed information and examples.
