Skip to content

Commit

Permalink
#15 Added account (#20)
Browse files Browse the repository at this point in the history
* resolves #15
  • Loading branch information
0xdfgp committed Jul 7, 2018
1 parent f580893 commit ab83851
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 0 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,22 @@ query := binance.NewGetAllOrdersQuery("LTCBTC").
response, _ := sdk.GetAllOrders(query)
```

### Account information (USER_DATA)
Get current account information.

Official doc: [Account information (USER_DATA)](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-information-user_data)

#### Example
```go
query := binance.NewAccountQuery()
response, _ := sdk.Account(query)

// With all optional parameters (See official doc)
query := binance.NewAccountQuery().RecvWindow(2000)
response, _ := sdk.Account(query)
```


## Available web socket streams:
Not available yet.

Expand Down
57 changes: 57 additions & 0 deletions account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package binance

import (
"encoding/json"
)

type Account struct {
MakerCommission int64
TakerCommission int64
BuyerCommission int64
SellerCommission int64
CanTrade bool
CanWithdraw bool
CanDeposit bool
UpdateTime int64
Balances []Balance
}

type Balance struct {
Asset string
Free float64 `json:"free,string"`
Locked float64 `json:"locked,string"`
}

type accountQuery struct {
recvWindow *int64
timestamp *int64
}

func NewAccountQuery() *accountQuery {
return &accountQuery{}
}

func (r *accountQuery) RecvWindow(value int64) *accountQuery {
r.recvWindow = &value
return r
}

func (sdk Sdk) Account(query *accountQuery) (*Account, error) {
req := newRequest("GET", "/api/v3/account").
Int64Param("recvWindow", query.recvWindow).
Int64Param("timestamp", sdk.clock.Now()).
Sign()

responseContent, err := sdk.client.Do(req)
if err != nil {
return nil, err
}

return parseAccountResponse(responseContent)
}

func parseAccountResponse(jsonContent []byte) (*Account, error) {
response := &Account{}
err := json.Unmarshal(jsonContent, &response)
return response, err
}
164 changes: 164 additions & 0 deletions account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package binance

import (
"errors"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"strconv"
"testing"
"time"
)

func TestSdk_Account(t *testing.T) {
method, url := "GET", "/api/v3/account"

t.Run("It should convert api response to an account", func(t *testing.T) {
ctrl := gomock.NewController(t)
mockedClock := NewMockClock(ctrl)
mockedClient := NewMockClient(ctrl)
sdk := Sdk{client: mockedClient, clock: mockedClock}

expectedTimestamp := time.Now().Unix()
mockedClock.EXPECT().Now().Return(&expectedTimestamp)

expectedRequest := newRequest(method, url).
Param("timestamp", strconv.FormatInt(expectedTimestamp, 10)).
Sign()

mockedClient.
EXPECT().
Do(expectedRequest).
MinTimes(1).
Return(validAccountJson(), nil)

query := NewAccountQuery()
response, _ := sdk.Account(query)

assert.Equal(t, validAccountResponse(), response)
})

t.Run("It should read optional parameters", func(t *testing.T) {
ctrl := gomock.NewController(t)
mockedClock := NewMockClock(ctrl)
mockedClient := NewMockClient(ctrl)
sdk := Sdk{client: mockedClient, clock: mockedClock}

expectedTimestamp := time.Now().Unix()
mockedClock.EXPECT().Now().Return(&expectedTimestamp)

expectedRequest := newRequest(method, url).
Param("recvWindow", "2").
Param("timestamp", strconv.FormatInt(expectedTimestamp, 10)).
Sign()

mockedClient.
EXPECT().
Do(expectedRequest).
MinTimes(1).
Return(validAccountJson(), nil)

query := NewAccountQuery().RecvWindow(2)
response, _ := sdk.Account(query)

assert.Equal(t, validAccountResponse(), response)
})

t.Run("It should return error when api fails", func(t *testing.T) {
ctrl := gomock.NewController(t)
mockedClock := NewMockClock(ctrl)
mockedClient := NewMockClient(ctrl)
sdk := Sdk{client: mockedClient, clock: mockedClock}

expectedTimestamp := time.Now().Unix()
mockedClock.EXPECT().Now().Return(&expectedTimestamp)

expectedRequest := newRequest(method, url).
Param("timestamp", strconv.FormatInt(expectedTimestamp, 10)).
Sign()

mockedClient.
EXPECT().
Do(expectedRequest).
MinTimes(1).
Return(nil, errors.New("error"))

query := NewAccountQuery()
_, err := sdk.Account(query)

assert.Error(t, err)
})

t.Run("It should return error when response cannot be mapped", func(t *testing.T) {
ctrl := gomock.NewController(t)
mockedClock := NewMockClock(ctrl)
mockedClient := NewMockClient(ctrl)
sdk := Sdk{client: mockedClient, clock: mockedClock}

expectedTimestamp := time.Now().Unix()
mockedClock.EXPECT().Now().Return(&expectedTimestamp)

expectedRequest := newRequest(method, url).
Param("timestamp", strconv.FormatInt(expectedTimestamp, 10)).
Sign()

mockedClient.
EXPECT().
Do(expectedRequest).
MinTimes(1).
Return(invalidJson(), nil)

query := NewAccountQuery()
_, err := sdk.Account(query)

assert.Error(t, err)
})
}

func validAccountJson() []byte {
return []byte(`{
"makerCommission": 15,
"takerCommission": 15,
"buyerCommission": 0,
"sellerCommission": 0,
"canTrade": true,
"canWithdraw": true,
"canDeposit": true,
"updateTime": 123456789,
"balances": [
{
"asset": "BTC",
"free": "4723846.89208129",
"locked": "0.00000000"
},
{
"asset": "LTC",
"free": "4763368.68006011",
"locked": "0.00000000"
}
]
}`)
}

func validAccountResponse() *Account {
return &Account{
MakerCommission: 15,
TakerCommission: 15,
BuyerCommission: 0,
SellerCommission: 0,
CanTrade: true,
CanWithdraw: true,
CanDeposit: true,
UpdateTime: 123456789,
Balances: []Balance{
{
Asset: "BTC",
Free: 4723846.89208129,
Locked: 0,
}, {
Asset: "LTC",
Free: 4763368.68006011,
Locked: 0,
},
},
}
}

0 comments on commit ab83851

Please sign in to comment.