2021-02-08 10:59:36 +00:00
|
|
|
package ftx
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
|
|
|
"testing"
|
2021-03-17 13:26:25 +00:00
|
|
|
"time"
|
2021-02-08 10:59:36 +00:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestExchange_QueryAccountBalances(t *testing.T) {
|
|
|
|
successResp := `
|
|
|
|
{
|
|
|
|
"result": [
|
|
|
|
{
|
|
|
|
"availableWithoutBorrow": 19.47458865,
|
|
|
|
"coin": "USD",
|
|
|
|
"free": 19.48085209,
|
|
|
|
"spotBorrow": 0.0,
|
|
|
|
"total": 1094.66405065,
|
|
|
|
"usdValue": 1094.664050651561
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"success": true
|
|
|
|
}
|
|
|
|
`
|
|
|
|
failureResp := `{"result":[],"success":false}`
|
|
|
|
i := 0
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if i == 0 {
|
|
|
|
fmt.Fprintln(w, successResp)
|
|
|
|
i++
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Fprintln(w, failureResp)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
ex := NewExchange("", "", "")
|
|
|
|
serverURL, err := url.Parse(ts.URL)
|
|
|
|
assert.NoError(t, err)
|
2021-03-15 11:01:23 +00:00
|
|
|
ex.restEndpoint = serverURL
|
2021-02-08 10:59:36 +00:00
|
|
|
resp, err := ex.QueryAccountBalances(context.Background())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Len(t, resp, 1)
|
|
|
|
b, ok := resp["USD"]
|
|
|
|
assert.True(t, ok)
|
|
|
|
expectedAvailable := fixedpoint.Must(fixedpoint.NewFromString("19.48085209"))
|
|
|
|
assert.Equal(t, expectedAvailable, b.Available)
|
|
|
|
assert.Equal(t, fixedpoint.Must(fixedpoint.NewFromString("1094.66405065")).Sub(expectedAvailable), b.Locked)
|
|
|
|
|
|
|
|
resp, err = ex.QueryAccountBalances(context.Background())
|
|
|
|
assert.EqualError(t, err, "ftx returns querying balances failure")
|
|
|
|
assert.Nil(t, resp)
|
|
|
|
}
|
2021-03-17 13:26:25 +00:00
|
|
|
|
|
|
|
func TestExchange_QueryOpenOrders(t *testing.T) {
|
|
|
|
successResp := `
|
|
|
|
{
|
|
|
|
"success": true,
|
|
|
|
"result": [
|
|
|
|
{
|
|
|
|
"createdAt": "2019-03-05T09:56:55.728933+00:00",
|
|
|
|
"filledSize": 10,
|
|
|
|
"future": "XRP-PERP",
|
|
|
|
"id": 9596912,
|
|
|
|
"market": "XRP-PERP",
|
|
|
|
"price": 0.306525,
|
|
|
|
"avgFillPrice": 0.306526,
|
|
|
|
"remainingSize": 31421,
|
|
|
|
"side": "sell",
|
|
|
|
"size": 31431,
|
|
|
|
"status": "open",
|
|
|
|
"type": "limit",
|
|
|
|
"reduceOnly": false,
|
|
|
|
"ioc": false,
|
|
|
|
"postOnly": false,
|
|
|
|
"clientId": null
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, successResp)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
ex := NewExchange("", "", "")
|
|
|
|
serverURL, err := url.Parse(ts.URL)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
ex.restEndpoint = serverURL
|
|
|
|
resp, err := ex.QueryOpenOrders(context.Background(), "XRP-PREP")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, resp, 1)
|
|
|
|
assert.Equal(t, "XRP-PERP", resp[0].Symbol)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExchange_QueryClosedOrders(t *testing.T) {
|
|
|
|
t.Run("no closed orders", func(t *testing.T) {
|
|
|
|
successResp := `{"success": true, "result": []}`
|
|
|
|
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, successResp)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
ex := NewExchange("", "", "")
|
|
|
|
serverURL, err := url.Parse(ts.URL)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
ex.restEndpoint = serverURL
|
|
|
|
resp, err := ex.QueryClosedOrders(context.Background(), "BTC-PERP", time.Time{}, time.Time{}, 100)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Len(t, resp, 0)
|
|
|
|
})
|
|
|
|
t.Run("one closed order", func(t *testing.T) {
|
|
|
|
successResp := `
|
|
|
|
{
|
|
|
|
"success": true,
|
|
|
|
"result": [
|
|
|
|
{
|
|
|
|
"avgFillPrice": 10135.25,
|
|
|
|
"clientId": null,
|
|
|
|
"createdAt": "2019-06-27T15:24:03.101197+00:00",
|
|
|
|
"filledSize": 0.001,
|
|
|
|
"future": "BTC-PERP",
|
|
|
|
"id": 257132591,
|
|
|
|
"ioc": false,
|
|
|
|
"market": "BTC-PERP",
|
|
|
|
"postOnly": false,
|
|
|
|
"price": 10135.25,
|
|
|
|
"reduceOnly": false,
|
|
|
|
"remainingSize": 0.0,
|
|
|
|
"side": "buy",
|
|
|
|
"size": 0.001,
|
|
|
|
"status": "closed",
|
|
|
|
"type": "limit"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"hasMoreData": false
|
|
|
|
}
|
|
|
|
`
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, successResp)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
ex := NewExchange("", "", "")
|
|
|
|
serverURL, err := url.Parse(ts.URL)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
ex.restEndpoint = serverURL
|
|
|
|
resp, err := ex.QueryClosedOrders(context.Background(), "BTC-PERP", time.Time{}, time.Time{}, 100)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, resp, 1)
|
|
|
|
assert.Equal(t, "BTC-PERP", resp[0].Symbol)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("sort the order", func(t *testing.T) {
|
|
|
|
successResp := `
|
|
|
|
{
|
|
|
|
"success": true,
|
|
|
|
"result": [
|
|
|
|
{
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "2020-09-01T15:24:03.101197+00:00",
|
|
|
|
"id": 789
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "2019-03-27T15:24:03.101197+00:00",
|
|
|
|
"id": 123
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "2019-06-27T15:24:03.101197+00:00",
|
|
|
|
"id": 456
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"status": "new",
|
|
|
|
"createdAt": "2019-06-27T15:24:03.101197+00:00",
|
|
|
|
"id": 999
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"hasMoreData": false
|
|
|
|
}
|
|
|
|
`
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, successResp)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
ex := NewExchange("", "", "")
|
|
|
|
serverURL, err := url.Parse(ts.URL)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
ex.restEndpoint = serverURL
|
|
|
|
resp, err := ex.QueryClosedOrders(context.Background(), "BTC-PERP", time.Time{}, time.Time{}, 100)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, resp, 3)
|
|
|
|
|
|
|
|
expectedOrderID := []uint64{123, 456, 789}
|
|
|
|
for i, o := range resp {
|
|
|
|
assert.Equal(t, expectedOrderID[i], o.OrderID)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("receive duplicated orders", func(t *testing.T) {
|
|
|
|
successRespOne := `
|
|
|
|
{
|
|
|
|
"success": true,
|
|
|
|
"result": [
|
|
|
|
{
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "2020-09-01T15:24:03.101197+00:00",
|
|
|
|
"id": 123
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"hasMoreData": true
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
successRespTwo := `
|
|
|
|
{
|
|
|
|
"success": true,
|
|
|
|
"result": [
|
|
|
|
{
|
|
|
|
"clientId": "ignored-by-created-at",
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "1999-09-01T15:24:03.101197+00:00",
|
|
|
|
"id": 999
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"clientId": "ignored-by-duplicated-id",
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "2020-09-02T15:24:03.101197+00:00",
|
|
|
|
"id": 123
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"clientId": "ignored-duplicated-entry",
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "2020-09-01T15:24:03.101197+00:00",
|
|
|
|
"id": 123
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"status": "closed",
|
|
|
|
"createdAt": "2020-09-02T15:24:03.101197+00:00",
|
|
|
|
"id": 456
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"hasMoreData": false
|
|
|
|
}
|
|
|
|
`
|
|
|
|
i := 0
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if i == 0 {
|
|
|
|
i++
|
|
|
|
fmt.Fprintln(w, successRespOne)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Fprintln(w, successRespTwo)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
ex := NewExchange("", "", "")
|
|
|
|
serverURL, err := url.Parse(ts.URL)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
ex.restEndpoint = serverURL
|
|
|
|
resp, err := ex.QueryClosedOrders(context.Background(), "BTC-PERP", time.Time{}, time.Time{}, 100)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, resp, 2)
|
|
|
|
expectedOrderID := []uint64{123, 456}
|
|
|
|
for i, o := range resp {
|
|
|
|
assert.Equal(t, expectedOrderID[i], o.OrderID)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|