From 569a9209e00ac065c249e4b9b48680fbc2cd9062 Mon Sep 17 00:00:00 2001 From: Dan Richards Date: Sat, 17 Feb 2018 22:18:38 +0000 Subject: [PATCH] Implemented Spread endpoint and tests. --- README.md | 4 +-- depth.go | 2 +- market.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ market_test.go | 47 +++++++++++++++++++++++++ spread.go | 25 ++++++++++++++ 5 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 spread.go diff --git a/README.md b/README.md index 059953a..b4a670b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Go Kraken [![GoDoc](https://godoc.org/github.com/danmrichards/gokraken?status.svg)](https://godoc.org/github.com/danmrichards/gokraken) [![License](http://img.shields.io/badge/license-mit_bsd-blue.svg)](https://raw.githubusercontent.com/danmrichards/gokraken/master/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/danmrichards/gokraken)](https://goreportcard.com/report/github.com/danmrichards/gokraken) [![Build Status](https://travis-ci.org/danmrichards/gokraken.svg?branch=master)](https://travis-ci.org/danmrichards/gokraken) A Go API client for the [Kraken](https://www.kraken.com) cryptocurrency exchange -> Note: This is stupidly early in development. Don't use it please...no really don't - ## Usage ### Public API ```go @@ -63,7 +61,7 @@ Coming soon - [x] Public API calls working - [x] Private API calls working - [x] Travis CI -- [ ] Implement public market data endpoints +- [x] Implement public market data endpoints - [ ] Implement private user data endpoints - [ ] Implement private user trading endpoints - [ ] Implement private user funding endpoints diff --git a/depth.go b/depth.go index 67d42f3..d0ea990 100644 --- a/depth.go +++ b/depth.go @@ -15,7 +15,7 @@ type DepthRequest struct { Count int } -// TradesResponse represents the response from the Kraken order book endpoint. +// DepthResponse represents the response from the Kraken order book endpoint. type DepthResponse map[string]Depth // Depth is an order book response for a given asset pair. diff --git a/market.go b/market.go index 27e47ac..b2a45e6 100644 --- a/market.go +++ b/market.go @@ -391,3 +391,97 @@ func (m *Market) Trades(ctx context.Context, tradeReq *TradesRequest) (res *Trad return } + +// Spread returns the spread data from Kraken. +// https://www.kraken.com/en-gb/help/api#get-recent-spread-data +func (m *Market) Spread(ctx context.Context, spreadReq *SpreadRequest) (res *SpreadResponse, err error) { + body := url.Values{ + "pair": []string{spreadReq.Pair}, + } + + if spreadReq.Since != 0 { + body["since"] = []string{strconv.FormatInt(spreadReq.Since, 10)} + } + + req, err := m.Client.Dial(ctx, http.MethodPost, SpreadResource, body) + if err != nil { + return + } + + krakenResp, err := m.Client.Call(req) + if err != nil { + return + } + + var tmp map[string]interface{} + err = krakenResp.ExtractResult(&tmp) + if err != nil { + return + } + + lastFloat, ok := tmp["last"].(float64) + if !ok { + err = errors.New("could not extract last from ohlc response") + return + } + + res = &SpreadResponse{ + Last: int64(lastFloat), + Data: make([]SpreadData, 0), + } + + spreadData, ok := tmp[spreadReq.Pair].([]interface{}) + if !ok { + err = fmt.Errorf("could not extract spread data where pair=%s", spreadReq.Pair) + return + } + + for key, spreadDatum := range spreadData { + spreadDatum, ok := spreadDatum.([]interface{}) + if !ok { + err = fmt.Errorf("could not extract at spreadDatum=%d", key) + return + } + + timestampFloat, ok := spreadDatum[0].(float64) + if !ok { + err = fmt.Errorf("could not extract timestamp at spreadDatum=%d", key) + return + } + timestamp := time.Unix(int64(timestampFloat), 0) + + bidStr, ok := spreadDatum[1].(string) + if !ok { + err = fmt.Errorf("could not extract bid at spreadDatum=%d", key) + return + } + + var bid float64 + bid, err = strconv.ParseFloat(bidStr, 64) + if err != nil { + err = fmt.Errorf("could not parse bid to float at spreadDatum=%d", key) + return + } + + askStr, ok := spreadDatum[2].(string) + if !ok { + err = fmt.Errorf("could not extract ask at spreadDatum=%d", key) + return + } + + var ask float64 + ask, err = strconv.ParseFloat(askStr, 64) + if err != nil { + err = fmt.Errorf("could not parse ask to float at spreadDatum=%d", key) + return + } + + res.Data = append(res.Data, SpreadData{ + Timestamp: timestamp, + Bid: bid, + Ask: ask, + }) + } + + return +} diff --git a/market_test.go b/market_test.go index ba4f21f..60efed9 100644 --- a/market_test.go +++ b/market_test.go @@ -687,3 +687,50 @@ func TestMarket_Trades(t *testing.T) { }) } } + +func TestMarket_Spread(t *testing.T) { + cases := []struct { + name string + request *SpreadRequest + mockResponse []byte + expectedResponse *SpreadResponse + }{ + { + name: "valid request", + request: &SpreadRequest{Pair: "BCHEUR"}, + mockResponse: []byte(`{"error":[],"result":{"BCHEUR":[[1518904771,"1225.600000","1229.200000"]],"last":1518905570}}`), + expectedResponse: &SpreadResponse{ + Data: []SpreadData{ + { + Timestamp: time.Unix(1518904771, 0), + Bid: 1225.6, + Ask: 1229.2, + }, + }, + Last: 1518905570, + }, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + w.Write(c.mockResponse) + })) + + defer ts.Close() + + k := New() + k.BaseURL = ts.URL + + res, err := k.Market.Spread(context.Background(), &SpreadRequest{Pair: "BCHEUR"}) + if err != nil { + t.Fatal(err) + } + + assert(c.expectedResponse, res, t) + }) + } +} diff --git a/spread.go b/spread.go new file mode 100644 index 0000000..b1a0f27 --- /dev/null +++ b/spread.go @@ -0,0 +1,25 @@ +package gokraken + +import "time" + +// SpreadResource is the API resource for the Kraken API spread data. +const SpreadResource = "Spread" + +// SpreadRequest represents a request to get spread data from Kraken. +type SpreadRequest struct { + Pair string + Since int64 +} + +// SpreadResponse represents the response from the Kraken spread data endpoint. +type SpreadResponse struct { + Data []SpreadData + Last int64 +} + +// SpreadData is the spread of data for trades. +type SpreadData struct { + Timestamp time.Time + Bid float64 + Ask float64 +}