Skip to content

Commit

Permalink
Implement public API (#6)
Browse files Browse the repository at this point in the history
* implement and test GetTickSizes

* implement and test GetMaximumTradeAmounts and GetApplicableFees

* implement GetSymbols

* implement and test HealthCheck and GetMinimumTradeAmounts

* go fmt

* mark public as ready in the README.md

Co-authored-by: Roman Akhtariev <[email protected]>
  • Loading branch information
p0mvn and akhtariev authored Oct 19, 2021
1 parent 5cdb4af commit 2bd3517
Show file tree
Hide file tree
Showing 3 changed files with 266 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ n := New(<ClientId>, <ClientSecret>)
TODO:

- [x] API for private endpoints
- [ ] API for public endpoints
- [x] API for public endpoints
- [ ] Add sandbox environment for unit tests
200 changes: 194 additions & 6 deletions newton.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,32 @@ type NewOrderReq struct {
Quantity float64 `json:"quantity"`
}

type GetTickSizesResp struct {
Ticks map[string]struct {
Tick float64 `json:"tick"`
}
}

type GetMaxTradeAmountsResp struct {
TradeAmounts map[string]struct {
Buy float64 `json:"buy"`
Sell float64 `json:"sell"`
}
}

type GetApplicableFeesResp struct {
Fees struct {
Maker float64 `json:"maker"`
Taker float64 `json:"taker"`
}
}

type GetMinTradeAmountsResp GetMaxTradeAmountsResp

type GetSymbolsResp struct {
Symbols []string
}

type BalancesResp struct {
Balances map[string]float64
}
Expand Down Expand Up @@ -147,14 +173,17 @@ func (n *Newton) sign(req *http.Request) error {
return nil
}

func doPublicQuery(path string, method string, args []Args, body string) (*http.Response, error) {
// Public API
///////////////////////////////////////////////////////////////////////////////////////////////////
func (n *Newton) doPublicQuery(path string, method string, args []Args, body string) (*http.Response, error) {
url := baseUrl + path

req, _ := http.NewRequest(method, url, nil)
q := req.URL.Query()
for _, a := range args {
q.Add(a.Key, a.Value)
}
req.URL.RawQuery = q.Encode()
if method != http.MethodGet {
_, err := req.Body.Read([]byte(body))
if err != nil {
Expand All @@ -168,6 +197,165 @@ func doPublicQuery(path string, method string, args []Args, body string) (*http.
return res, err
}

func (n *Newton) GetTickSizes() (*GetTickSizesResp, error) {
res, err := n.doPublicQuery("/order/tick-sizes", http.MethodGet, []Args{}, "")
if err != nil {
return nil, err
}
defer func() {
err := res.Body.Close()
if err != nil {
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

body, _ := ioutil.ReadAll(res.Body)

var resp GetTickSizesResp
err = json.Unmarshal(body, &resp.Ticks)
if err != nil {
return nil, err
}

return &resp, nil
}

func (n *Newton) GetMaximumTradeAmounts() (*GetMaxTradeAmountsResp, error) {
res, err := n.doPublicQuery("/order/maximums", http.MethodGet, []Args{}, "")
if err != nil {
return nil, err
}
defer func() {
err := res.Body.Close()
if err != nil {
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

body, _ := ioutil.ReadAll(res.Body)

var resp GetMaxTradeAmountsResp
err = json.Unmarshal(body, &resp.TradeAmounts)
if err != nil {
return nil, err
}

return &resp, nil
}

func (n *Newton) GetApplicableFees() (*GetApplicableFeesResp, error) {
res, err := n.doPublicQuery("/fees", http.MethodGet, []Args{}, "")
if err != nil {
return nil, err
}
defer func() {
err := res.Body.Close()
if err != nil {
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

body, _ := ioutil.ReadAll(res.Body)

var resp GetApplicableFeesResp
err = json.Unmarshal(body, &resp.Fees)
if err != nil {
return nil, err
}

return &resp, nil
}

func (n *Newton) GetSymbols(baseAsset, quoteAsset string) (*GetSymbolsResp, error) {
args := []Args{}
if baseAsset != "" {
args = append(args, Args{Key: "base_asset", Value: baseAsset})
}

if quoteAsset != "" {
args = append(args, Args{Key: "quote_asset", Value: quoteAsset})
}

res, err := n.doPublicQuery("/symbols", http.MethodGet, args, "")
if err != nil {
return nil, err
}
defer func() {
err := res.Body.Close()
if err != nil {
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

body, _ := ioutil.ReadAll(res.Body)

var resp GetSymbolsResp
err = json.Unmarshal(body, &resp.Symbols)
if err != nil {
return nil, err
}

return &resp, nil
}

func (n *Newton) HealthCheck() error {
res, err := n.doPublicQuery("/symbols", http.MethodGet, []Args{}, "")
if err != nil {
return err
}
defer func() {
err := res.Body.Close()
if err != nil {
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != http.StatusOK {
return errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

return nil
}

func (n *Newton) GetMinimumTradeAmount() (*GetMinTradeAmountsResp, error) {
res, err := n.doPublicQuery("/order/minimums", http.MethodGet, []Args{}, "")
if err != nil {
return nil, err
}
defer func() {
err := res.Body.Close()
if err != nil {
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

body, _ := ioutil.ReadAll(res.Body)

var resp GetMinTradeAmountsResp
err = json.Unmarshal(body, &resp.TradeAmounts)
if err != nil {
return nil, err
}

return &resp, nil
}

// Private API
///////////////////////////////////////////////////////////////////////////////////////////////////
func (n *Newton) doPrivateQuery(path string, method string, args []Args, body string) (*http.Response, error) {
url := baseUrl + path

Expand Down Expand Up @@ -205,7 +393,7 @@ func (n *Newton) Balances(asset string) (*BalancesResp, error) {
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != 200 {
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

Expand Down Expand Up @@ -250,7 +438,7 @@ func (n *Newton) Actions(actionType ActionType, limit int, offset int, startDate
}
}()
body, _ := ioutil.ReadAll(res.Body)
if res.StatusCode != 200 {
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

Expand Down Expand Up @@ -296,7 +484,7 @@ func (n *Newton) OrdersHistory(limit int, offset int, startDate int64, endDate i
}
}()
body, _ := ioutil.ReadAll(res.Body)
if res.StatusCode != 200 {
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

Expand Down Expand Up @@ -335,7 +523,7 @@ func (n *Newton) OpenOrders(limit int, offset int, symbol string, timeInForce st
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != 200 {
if res.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("request failed :: %d", res.StatusCode))
}

Expand Down Expand Up @@ -369,7 +557,7 @@ func (n *Newton) NewOrder(orderType string, timeInForce string, side string, sym
log.Printf("error:%s", err.Error())
}
}()
if res.StatusCode != 200 {
if res.StatusCode != http.StatusOK {
body, _ := ioutil.ReadAll(res.Body)
return nil, errors.New(fmt.Sprintf("request failed :: %d %s", res.StatusCode, body))
}
Expand Down
71 changes: 71 additions & 0 deletions newton_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package newton

import (
"os"
"testing"
"time"
)
Expand All @@ -9,6 +10,76 @@ func getSecrets() (string, string) {
return os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET")
}

// Public API
///////////////////////////////////////////////////////////////////////////////////////////////////
func TestGetTickSizes(t *testing.T) {
ClientId, ClientSecret := getSecrets()
n := New(ClientId, ClientSecret)

_, err := n.GetTickSizes()

if err != nil {
t.Error("test failed: " + err.Error())
}
}

func TestGetMaximumTradeAmounts(t *testing.T) {
ClientId, ClientSecret := getSecrets()
n := New(ClientId, ClientSecret)

_, err := n.GetMaximumTradeAmounts()

if err != nil {
t.Error("test failed: " + err.Error())
}
}

func TestGetApplicableFees(t *testing.T) {
ClientId, ClientSecret := getSecrets()
n := New(ClientId, ClientSecret)

_, err := n.GetApplicableFees()

if err != nil {
t.Error("test failed: " + err.Error())
}
}

func TestSymbolsNoQuery(t *testing.T) {
ClientId, ClientSecret := getSecrets()
n := New(ClientId, ClientSecret)

_, err := n.GetSymbols("", "")

if err != nil {
t.Error("test failed: " + err.Error())
}
}

func TestHealthCheck(t *testing.T) {
ClientId, ClientSecret := getSecrets()
n := New(ClientId, ClientSecret)

err := n.HealthCheck()

if err != nil {
t.Error("test failed: " + err.Error())
}
}

func TestGetMinTradeAmounts(t *testing.T) {
ClientId, ClientSecret := getSecrets()
n := New(ClientId, ClientSecret)

_, err := n.GetMinimumTradeAmount()

if err != nil {
t.Error("test failed: " + err.Error())
}
}

// Private API
///////////////////////////////////////////////////////////////////////////////////////////////////
func TestBalance(t *testing.T) {
ClientId, ClientSecret := getSecrets()
n := New(ClientId, ClientSecret)
Expand Down

0 comments on commit 2bd3517

Please sign in to comment.