For information on changes for our US clients, please visit our Support Center article.

Example code for Go REST and WebSocket API

Introduction

Below is a Go example script that can be referenced for both the REST and WebSocket Implementation of the Kraken API.

It demo's the following functionality:
  • Public REST API Endpoints
  • Private REST API Endpoints
  • Public WebSocket API Subscriptions
  • Private WebSocket API Subscriptions

Installation

To run locally, you can copy/paste the code below.

Note that setting the if statement of 1 == 0 to 1 == 1 will execute the specific block of code.

Before running the script, you need to update the script with your Public and Private API Keys.

You can download this file here.

Go Code

golang

Golang

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "crypto/sha512"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "os/signal"
    "strings"
    "time"

    "github.com/sacOO7/gowebsocket"
)

// WsTokenJsonStruct represents the JSON structure of the WebSocket token response
type WsTokenJsonStruct struct {
    Error []interface{} `json:"error"`
    Result struct {
        Token string `json:"token"`
        Expires int `json:"expires"`
    } `json:"result"`
}

func main() {
    // TODO: Replace the Public and Private key with YOUR keys :)
    apiPublicKey := "YOUR_PUBLIC_KEY"
    apiPrivateKey := "YOUR_PRIVATE_KEY"

    fmt.Println("|==========================================|")
    fmt.Println("| KRAKEN.COM GOLANG TEST APP |")
    fmt.Println("|==========================================|")
    fmt.Println()

    // PUBLIC REST API Examples
    if 1 == 0 {
        publicEndpoint := "SystemStatus"
        publicInputParameters := ""

        // MORE PUBLIC REST EXAMPLES
        // publicEndpoint := "AssetPairs"
        // publicInputParameters := "pair=ethusd,xbtusd"
        // publicEndpoint := "Ticker"
        // publicInputParameters := "pair=ethusd"
        // publicEndpoint := "Trades"
        // publicInputParameters := "pair=ethusd&since=0"

        publicResponse := QueryPublicEndpoint(publicEndpoint, publicInputParameters)
        fmt.Println(publicResponse)
    }

    // PRIVATE REST API Examples
    if 0 == 0 {
        privateEndpoint := "Balance"
        privateInputParameters := ""

        // MORE PRIVATE REST EXAMPLES
        // privateEndpoint := "AddOrder"
        // privateInputParameters := "pair=xbteur&type=buy&ordertype=limit&price=1.00&volume=1"
        // privateEndpoint := "AddOrder"
        // privateInputParameters := "pair=xdgeur&type=sell&ordertype=limit&volume=3000&price=%2b10.0%" // Positive Percentage Example (%2 represents +, which is a reserved character in HTTP)
        // privateEndpoint := "AddOrder"
        // privateInputParameters := "pair=xdgeur&type=sell&ordertype=limit&volume=3000&price=-10.0%" // Negative Percentage Example
        // privateEndpoint := "AddOrder"
        // privateInputParameters := "pair=xdgeur&type=buy&ordertype=market&volume=3000&userref=789" // Userref Example
        // privateEndpoint := "Balance" // {"error":[]} IS SUCCESS, Means EMPTY BALANCE
        // privateInputParameters := ""
        // privateEndpoint := "QueryOrders"
        // privateInputParameters := "txid=OFUSL6-GXIIT-KZ2JDJ"
        // privateEndpoint := "AddOrder"
        // privateInputParameters := "pair=xdgusd&type=buy&ordertype=market&volume=5000"
        // privateEndpoint := "DepositAddresses"
        // privateInputParameters := "asset=xbt&method=Bitcoin"
        // privateEndpoint := "DepositMethods"
        // privateInputParameters := "asset=eth"
        // privateEndpoint := "WalvarTransfer"
        // privateInputParameters := "asset=xbt&to=Futures Walvar&from=Spot Walvar&amount=0.0045"
        // privateEndpoint := "TradesHistory"
        // privateInputParameters := "start=1577836800&end=1609459200"
        // privateEndpoint := "GetWebSocketsToken"
        // privateInputParameters := ""

        privateResponse := QueryPrivateEndpoint(privateEndpoint, privateInputParameters, apiPublicKey, apiPrivateKey)
        fmt.Println(privateResponse)
    }

    // PUBLIC WEBSOCKET Examples
    if 1 == 0 {
        publicWebSocketURL := "wss://ws.kraken.com/"
        publicWebSocketSubscriptionMsg := "{ \"event\":\"subscribe\", \"subscription\":{\"name\":\"trade\"},\"pair\":[\"XBT/USD\"] }"

        // MORE PUBLIC WEBSOCKET EXAMPLES
        // publicWebSocketSubscriptionMsg := "{ \"event\": \"subscribe\", \"subscription\": { \"interval\": 1440, \"name\": \"ohlc\"}, \"pair\": [ \"XBT/EUR\"]}"
        // publicWebSocketSubscriptionMsg := "{ \"event\": \"subscribe\", \"subscription\": { \"name\": \"spread\"}, \"pair\": [ \"XBT/EUR\",\"ETH/USD\" ]}"

        OpenAndStreamWebSocketSubscription(publicWebSocketURL, publicWebSocketSubscriptionMsg)
    }

    // PRIVATE WEBSOCKET Examples
    if 1 == 0 {
        privateWebSocketURL := "wss://ws-auth.kraken.com/"

        // GET THE WEBSOCKET TOKEN FORM THE JSON RESPONSE
        response := GetWebSocketToken("GetWebSocketsToken", "", apiPublicKey, apiPrivateKey)
        webSocketToken := response.Result.Token

        // MORE PRIVATE WEBSOCKET EXAMPLES
        // privateWebSocketSubscriptionMsg := "{\"event\": \"subscribe\", \"subscription\": { \"name\": \"openOrders\", \"token\": \"" + webSocketToken + "\"}}"
        // privateWebSocketSubscriptionMsg := "{\"event\": \"subscribe\", \"subscription\": { \"name\": \"balances\", \"token\": \"" + webSocketToken + "\"}}"
        // privateWebSocketSubscriptionMsg := "{\"event\":\"addOrder\",\"reqid\":1234,\"ordertype\":\"limit\",\"pair\":\"XBT/EUR\",\"token\": \"" + webSocketToken + "\",\"type\":\"buy\",\"volume\":\"1\", \"price\":\"1.00\"}"

        // REPLACE PLACEHOLDER WITH TOKEN
        privateWebSocketSubscriptionMsg := "{ \"event\": \"subscribe\", \"subscription\": { \"name\": \"ownTrades\", \"token\": \"" + webSocketToken + "\"}}"

        OpenAndStreamWebSocketSubscription(privateWebSocketURL, privateWebSocketSubscriptionMsg)
    }

    fmt.Println()
    fmt.Println("|=======================================|")
    fmt.Println("| END OF PROGRAM - HAVE A GOOD DAY :) |")
    fmt.Println("|=======================================|")
    fmt.Println("\n")
}

// QueryPublicEndpoint queries a public endpoint on the Kraken API
func QueryPublicEndpoint(endPointName, inputParameters string) string {
    baseDomain := "https://api.kraken.com"
    publicPath := "/0/public/"
    apiEndpointFullURL := baseDomain + publicPath + endPointName + "?" + inputParameters

    resp, err := http.Get(apiEndpointFullURL)
    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }

    return string(body)
}

// QueryPrivateEndpoint queries a private endpoint on the Kraken API
func QueryPrivateEndpoint(endPointName, inputParameters, apiPublicKey, apiPrivateKey string) string {
    baseDomain := "https://api.kraken.com"
    privatePath := "/0/private/"
    apiEndpointFullURL := baseDomain + privatePath + endPointName + "?" + inputParameters

    nonce := fmt.Sprintf("%d", time.Now().Unix())
    apiPostBodyData := "nonce=" + nonce + "&" + inputParameters
    signature := CreateAuthenticationSignature(apiPrivateKey, privatePath, endPointName, nonce, apiPostBodyData)

    httpOptions, err := http.NewRequest("POST", apiEndpointFullURL, strings.NewReader(apiPostBodyData))
    httpOptions.Header.Add("API-Key", apiPublicKey)
    httpOptions.Header.Add("API-Sign", signature)
    httpOptions.Header.Add("User-Agent", "GO Lang Client")

    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }

    resp, err := http.DefaultClient.Do(httpOptions)
    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }

    jsonData := string(body)
    return jsonData
}

// GetWebSocketToken gets a WebSocket token from the Kraken API
func GetWebSocketToken(endPointName, inputParameters, apiPublicKey, apiPrivateKey string) WsTokenJsonStruct {
    baseDomain := "https://api.kraken.com"
    privatePath := "/0/private/"
    apiEndpointFullURL := baseDomain + privatePath + endPointName + "?" + inputParameters

    nonce := fmt.Sprintf("%d", time.Now().Unix())
    apiPostBodyData := "nonce=" + nonce + "&" + inputParameters
    signature := CreateAuthenticationSignature(apiPrivateKey, privatePath, endPointName, nonce, apiPostBodyData)

    httpOptions, err := http.NewRequest("POST", apiEndpointFullURL, strings.NewReader(apiPostBodyData))
    httpOptions.Header.Add("API-Key", apiPublicKey)
    httpOptions.Header.Add("API-Sign", signature)
    httpOptions.Header.Add("User-Agent", "GO Lang Client")

    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }

    resp, err := http.DefaultClient.Do(httpOptions)
    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("ERROR OCCURED: ", err)
        os.Exit(1)
    }

    var jsonData WsTokenJsonStruct
    json.Unmarshal(body, &jsonData)
    return jsonData
}

// CreateAuthenticationSignature creates an authentication signature for the Kraken API
func CreateAuthenticationSignature(apiPrivateKey, apiPath, endPointName, nonce, apiPostBodyData string) string {
    apiPost := nonce + apiPostBodyData
    secret, _ := base64.StdEncoding.DecodeString(apiPrivateKey)
    apiEndpointPath := apiPath + endPointName
    sha := sha256.New()
    sha.Write([]byte(apiPost))
    shaSum := sha.Sum(nil)
    allBytes := append([]byte(apiEndpointPath), shaSum...)
    mac := hmac.New(sha512.New, secret)
    mac.Write(allBytes)
    macSum := mac.Sum(nil)
    signatureString := base64.StdEncoding.EncodeToString(macSum)
    return signatureString
}

// OpenAndStreamWebSocketSubscription opens and streams a WebSocket subscription
func OpenAndStreamWebSocketSubscription(connectionURL, webSocketSubscription string) {
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    webSocketClient := gowebsocket.New(connectionURL)

    webSocketClient.OnConnectError = func(err error, socket gowebsocket.Socket) {
        fmt.Println("Received connect error - ", err)
    }

    webSocketClient.OnConnected = func(socket gowebsocket.Socket) {
        fmt.Println("Connected to server")
    }

    webSocketClient.OnTextMessage = func(message string, socket gowebsocket.Socket) {
        fmt.Println(time.Now().Format("01-02-2006 15:04:05") + ": " + message)
    }

    webSocketClient.OnPingReceived = func(message string, socket gowebsocket.Socket) {
        fmt.Println("Received ping - " + message)
    }

    webSocketClient.OnPongReceived = func(message string, socket gowebsocket.Socket) {
        fmt.Println("Received pong - " + message)
    }

    webSocketClient.OnDisconnected = func(err error, socket gowebsocket.Socket) {
        fmt.Println("Socket Closed")
        fmt.Println("\n")
    }

    webSocketClient.Connect()
    webSocketClient.SendText(webSocketSubscription)

    for {
        select {
        case <-interrupt:
            log.Println("interrupt")
            webSocketClient.Close()
            return
        }
    }
}

Need more help?