diff --git a/.gitignore b/.gitignore index 85704dd..36a5089 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -*.DS_Store -*.vscode \ No newline at end of file +*.DS_Store +*.vscode +.env diff --git a/go.mod b/go.mod index 7f54dfa..8e55fdd 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/go-numb/go-ftx +module github.com/boyi/go-ftx go 1.14 diff --git a/realtime/websocket.go b/realtime/websocket.go index a3927b5..93f000b 100644 --- a/realtime/websocket.go +++ b/realtime/websocket.go @@ -11,11 +11,11 @@ import ( "os" "time" + "github.com/boyi/go-ftx/rest/private/fills" + "github.com/boyi/go-ftx/rest/private/orders" + "github.com/boyi/go-ftx/rest/public/markets" + "github.com/boyi/go-ftx/types" "github.com/buger/jsonparser" - "github.com/go-numb/go-ftx/rest/private/fills" - "github.com/go-numb/go-ftx/rest/private/orders" - "github.com/go-numb/go-ftx/rest/public/markets" - "github.com/go-numb/go-ftx/types" "github.com/gorilla/websocket" ) diff --git a/realtime/websocket_test.go b/realtime/websocket_test.go index 8b62be6..29a4d9c 100644 --- a/realtime/websocket_test.go +++ b/realtime/websocket_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/go-numb/go-ftx/realtime" + "github.com/boyi/go-ftx/realtime" ) func TestConnect(t *testing.T) { diff --git a/rest/client.go b/rest/client.go index c48f9d8..886066b 100644 --- a/rest/client.go +++ b/rest/client.go @@ -3,7 +3,7 @@ package rest import ( "time" - "github.com/go-numb/go-ftx/auth" + "github.com/boyi/go-ftx/auth" jsoniter "github.com/json-iterator/go" "github.com/valyala/fasthttp" ) diff --git a/rest/private/convert/accept-quote.go b/rest/private/convert/accept-quote.go new file mode 100644 index 0000000..ac9b6bd --- /dev/null +++ b/rest/private/convert/accept-quote.go @@ -0,0 +1,30 @@ +package convert + +import ( + "fmt" + "net/http" +) + +type RequestForAcceptQuote struct { + QuoteId int `json:"quoteId"` +} + +type ResponseForAcceptQuote struct { + // Filled bool `json:"filled"` +} + +func (req *RequestForAcceptQuote) Path() string { + return fmt.Sprintf("/otc/quotes/%d/accept", req.QuoteId) +} + +func (req *RequestForAcceptQuote) Method() string { + return http.MethodPost +} + +func (req *RequestForAcceptQuote) Query() string { + return "" +} + +func (req *RequestForAcceptQuote) Payload() []byte { + return nil +} diff --git a/rest/private/convert/get-quote-status.go b/rest/private/convert/get-quote-status.go new file mode 100644 index 0000000..cad4493 --- /dev/null +++ b/rest/private/convert/get-quote-status.go @@ -0,0 +1,41 @@ +package convert + +import ( + "fmt" + "net/http" +) + +type RequestForQuoteStatus struct { + QuoteId int `json:"quoteId"` +} + +type ResponseForQuoteStatus struct { + BaseCoin string `json:"baseCoin"` + Cost float64 `json:"cost"` + Expired bool `json:"expired"` + Expiry float64 `json:"expiry"` + Filled bool `json:"filled"` + FromCoin string `json:"fromCoin"` + QuoteId int `json:"id"` + Price float64 `json:"price"` + Proceeds float64 `json:"proceeds"` + QuoteCoin string `json:"quoteCoin"` + Side string `json:"side"` + ToCoin string `json:"toCoin"` +} + +func (req *RequestForQuoteStatus) Path() string { + return fmt.Sprintf("/otc/quotes/%d", req.QuoteId) +} + +func (req *RequestForQuoteStatus) Method() string { + return http.MethodGet +} + +func (req *RequestForQuoteStatus) Query() string { + return "" +} + +func (req *RequestForQuoteStatus) Payload() []byte { + return nil +} diff --git a/rest/private/convert/request-quote.go b/rest/private/convert/request-quote.go new file mode 100644 index 0000000..3de561a --- /dev/null +++ b/rest/private/convert/request-quote.go @@ -0,0 +1,37 @@ +package convert + +import ( + "encoding/json" + "net/http" +) + +type RequestForRequestQuote struct { + FromCoin string `json:"fromCoin"` + ToCoin string `json:"toCoin"` + Size float64 `json:"size"` + // WaitForPrice bool `json:"waitForPrice,omitempty"` +} + +type ResponseForRequestQuote struct { + QuoteId int `json:"quoteId"` +} + +func (req *RequestForRequestQuote) Path() string { + return "/otc/quotes" +} + +func (req *RequestForRequestQuote) Method() string { + return http.MethodPost +} + +func (req *RequestForRequestQuote) Query() string { + return "" +} + +func (req *RequestForRequestQuote) Payload() []byte { + b, err := json.Marshal(req) + if err != nil { + return nil + } + return b +} diff --git a/rest/private/convert/request-quote_test.go b/rest/private/convert/request-quote_test.go new file mode 100644 index 0000000..4e2a50a --- /dev/null +++ b/rest/private/convert/request-quote_test.go @@ -0,0 +1,112 @@ +package convert_test + +import ( + "fmt" + "os" + "testing" + + "github.com/boyi/go-ftx/auth" + "github.com/boyi/go-ftx/rest" + "github.com/boyi/go-ftx/rest/private/account" + "github.com/boyi/go-ftx/rest/private/convert" + "github.com/stretchr/testify/assert" +) + +func getAuth() *rest.Client { + subaccountNickname := os.Getenv("FTXSUBACCOUNT") + + if subaccountNickname == "" { + return rest.New(auth.New(os.Getenv("FTXKEY"), os.Getenv("FTXSECRET"))) + } + + c := rest.New(auth.New(os.Getenv("FTXKEY"), os.Getenv("FTXSECRET"), + auth.SubAccount{ + UUID: 1, + Nickname: subaccountNickname, + })) + c.Auth.UseSubAccountID(1) + return c +} + +func TestInformation(t *testing.T) { + c := getAuth() + + res, err := c.Information(&account.RequestForInformation{}) + assert.NoError(t, err) + + fmt.Printf("%+v\n", res) +} + +func GetQuote() (resp *convert.ResponseForRequestQuote, err error) { + c := getAuth() + + res, err := c.RequestConvertQuote(&convert.RequestForRequestQuote{ + FromCoin: "USDT", + ToCoin: "USD", + Size: 2, + }) + return res, err +} + +func TestRequestQuote(t *testing.T) { + quote, err := GetQuote() + assert.NoError(t, err) + assert.NotZero(t, quote.QuoteId) + quoteId := quote.QuoteId + + fmt.Printf("QuoteID: %+v\n", quoteId) +} + +func GetQuoteStatus(quoteId int) (resp *convert.ResponseForQuoteStatus, err error) { + c := getAuth() + + res, err := c.GetConvertQuoteStatus(&convert.RequestForQuoteStatus{ + QuoteId: quoteId, + }) + + return res, err +} + +func TestQuoteStatus(t *testing.T) { + quote, err := GetQuote() + assert.NoError(t, err) + assert.NotZero(t, quote.QuoteId) + quoteId := quote.QuoteId + fmt.Printf("Got quote with ID: %+v\n", quoteId) + + res, err := GetQuoteStatus(quoteId) + + assert.NoError(t, err) + assert.Equal(t, res.QuoteId, quoteId) + assert.NotZero(t, res.Price) + + fmt.Printf("Result: %+v\n", res) +} + +func AcceptQuote(quoteId int) (resp *convert.ResponseForAcceptQuote, err error) { + c := getAuth() + + res, err := c.AcceptConvertQuote(&convert.RequestForAcceptQuote{ + QuoteId: quoteId, + }) + + return res, err +} + +func TestAcceptQuote(t *testing.T) { + quote, err := GetQuote() + assert.NoError(t, err) + assert.NotZero(t, quote.QuoteId) + quoteId := quote.QuoteId + fmt.Printf("Got quote with ID: %+v\n", quoteId) + + res_status, err := GetQuoteStatus(quoteId) + assert.NoError(t, err) + assert.Equal(t, res_status.QuoteId, quoteId) + assert.NotZero(t, res_status.Cost) + fmt.Printf("Got quote status: %+v\n", res_status) + + res_accept, err := AcceptQuote(quoteId) + assert.NoError(t, err) + fmt.Printf("Accepted quote: %+v\n", res_accept) +} diff --git a/rest/private/wallet/deposit-histories.go b/rest/private/wallet/deposit-histories.go index f2b7aa6..efecb90 100644 --- a/rest/private/wallet/deposit-histories.go +++ b/rest/private/wallet/deposit-histories.go @@ -6,6 +6,8 @@ import ( ) type RequestForDepositHistories struct { + StartTime time.Time `url:"start_time,omitempty"` + EndTime time.Time `url:"end_time,omitempty"` } type ResponseForDepositHistories []History diff --git a/rest/private/wallet/withdraw-histories.go b/rest/private/wallet/withdraw-histories.go index 368b6fe..e1e4206 100644 --- a/rest/private/wallet/withdraw-histories.go +++ b/rest/private/wallet/withdraw-histories.go @@ -19,7 +19,7 @@ type Withdraw struct { Method string `json:"method"` Fee float64 `json:"fee"` - Size float64 `json:"size,string"` + Size float64 `json:"size"` Time time.Time `json:"time"` diff --git a/rest/private/wallet/withdraw.go b/rest/private/wallet/withdraw.go index ec781ca..6aa9380 100644 --- a/rest/private/wallet/withdraw.go +++ b/rest/private/wallet/withdraw.go @@ -2,6 +2,7 @@ package wallet import ( "net/http" + "time" ) type RequestForWithdraw struct { @@ -16,6 +17,15 @@ type RequestForWithdraw struct { } type ResponseForWithdraw struct { + Coin string `json:"coin,omitempty"` + Address string `json:"address,omitempty"` + Tag string `json:"tag,omitempty"` + Fee float64 `json:"fee,omitempty"` + ID int64 `json:"id,omitempty"` + Size float64 `json:"size,omitempty"` + Status string `json:"status,omitempty"` // one of "requested", "processing", "complete", or "cancelled" + Time time.Time `json:"time,omitempty"` + TxID string `json:"txid,omitempty"` } func (req *RequestForWithdraw) Path() string { diff --git a/rest/public/markets/trades.go b/rest/public/markets/trades.go index c4fa62e..7ec3bd3 100644 --- a/rest/public/markets/trades.go +++ b/rest/public/markets/trades.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - "github.com/go-numb/go-ftx/types" + "github.com/boyi/go-ftx/types" "github.com/google/go-querystring/query" ) diff --git a/rest/request-lev-options.go b/rest/request-lev-options.go index 3815ff3..6013ec1 100644 --- a/rest/request-lev-options.go +++ b/rest/request-lev-options.go @@ -1,8 +1,8 @@ package rest import ( - "github.com/go-numb/go-ftx/rest/private/leveraged" - "github.com/go-numb/go-ftx/rest/private/options" + "github.com/boyi/go-ftx/rest/private/leveraged" + "github.com/boyi/go-ftx/rest/private/options" ) /* diff --git a/rest/request-lev-options_test.go b/rest/request-lev-options_test.go index 1f211da..784d4cf 100644 --- a/rest/request-lev-options_test.go +++ b/rest/request-lev-options_test.go @@ -7,14 +7,14 @@ import ( "testing" "time" - "github.com/go-numb/go-ftx/auth" - "github.com/go-numb/go-ftx/types" + "github.com/boyi/go-ftx/auth" + "github.com/boyi/go-ftx/types" "github.com/stretchr/testify/assert" - "github.com/go-numb/go-ftx/rest" - "github.com/go-numb/go-ftx/rest/private/leveraged" - "github.com/go-numb/go-ftx/rest/private/options" + "github.com/boyi/go-ftx/rest" + "github.com/boyi/go-ftx/rest/private/leveraged" + "github.com/boyi/go-ftx/rest/private/options" ) /* diff --git a/rest/request-private.go b/rest/request-private.go index a57da06..fbdd26f 100644 --- a/rest/request-private.go +++ b/rest/request-private.go @@ -1,15 +1,17 @@ package rest import ( - "github.com/go-numb/go-ftx/rest/private/account" - "github.com/go-numb/go-ftx/rest/private/fills" - "github.com/go-numb/go-ftx/rest/private/funding" - "github.com/go-numb/go-ftx/rest/private/orders" - "github.com/go-numb/go-ftx/rest/private/spotmargin" - "github.com/go-numb/go-ftx/rest/private/subaccount" - "github.com/go-numb/go-ftx/rest/private/wallet" + "github.com/boyi/go-ftx/rest/private/account" + "github.com/boyi/go-ftx/rest/private/fills" + "github.com/boyi/go-ftx/rest/private/funding" + "github.com/boyi/go-ftx/rest/private/orders" + "github.com/boyi/go-ftx/rest/private/spotmargin" + "github.com/boyi/go-ftx/rest/private/subaccount" + "github.com/boyi/go-ftx/rest/private/wallet" + "github.com/boyi/go-ftx/rest/private/convert" ) + func (p *Client) Information(req *account.RequestForInformation) (*account.ResponseForInformation, error) { results := new(account.ResponseForInformation) if err := p.request(req, results); err != nil { @@ -311,3 +313,30 @@ func (p *Client) TransferSubAccount(req *subaccount.RequestForTransferSubAccount } return results, nil } + +/* + # Convert +*/ +func (p *Client) RequestConvertQuote(req *convert.RequestForRequestQuote) (*convert.ResponseForRequestQuote, error) { + results := new(convert.ResponseForRequestQuote) + if err := p.request(req, results); err != nil { + return nil, err + } + return results, nil +} + +func (p *Client) GetConvertQuoteStatus(req *convert.RequestForQuoteStatus) (*convert.ResponseForQuoteStatus, error) { + results := new(convert.ResponseForQuoteStatus) + if err := p.request(req, results); err != nil { + return nil, err + } + return results, nil +} + +func (p *Client) AcceptConvertQuote(req *convert.RequestForAcceptQuote) (*convert.ResponseForAcceptQuote, error) { + results := new(convert.ResponseForAcceptQuote) + if err := p.request(req, results); err != nil { + return nil, err + } + return results, nil +} diff --git a/rest/request-private_test.go b/rest/request-private_test.go index 75af8c6..7b0b139 100644 --- a/rest/request-private_test.go +++ b/rest/request-private_test.go @@ -7,18 +7,18 @@ import ( "testing" "time" - "github.com/go-numb/go-ftx/auth" + "github.com/boyi/go-ftx/auth" "github.com/stretchr/testify/assert" - "github.com/go-numb/go-ftx/rest" - "github.com/go-numb/go-ftx/rest/private/account" - "github.com/go-numb/go-ftx/rest/private/fills" - "github.com/go-numb/go-ftx/rest/private/orders" - "github.com/go-numb/go-ftx/rest/private/spotmargin" - "github.com/go-numb/go-ftx/rest/private/subaccount" - "github.com/go-numb/go-ftx/rest/private/wallet" - "github.com/go-numb/go-ftx/types" + "github.com/boyi/go-ftx/rest" + "github.com/boyi/go-ftx/rest/private/account" + "github.com/boyi/go-ftx/rest/private/fills" + "github.com/boyi/go-ftx/rest/private/orders" + "github.com/boyi/go-ftx/rest/private/spotmargin" + "github.com/boyi/go-ftx/rest/private/subaccount" + "github.com/boyi/go-ftx/rest/private/wallet" + "github.com/boyi/go-ftx/types" ) func TestURIEncode(t *testing.T) { @@ -315,8 +315,8 @@ func TestGetLendingHistory(t *testing.T) { c := rest.New(auth.New(os.Getenv("FTXKEY"), os.Getenv("FTXSECRET"))) res, err := c.GetLendingHistory(&spotmargin.RequestForLendingHistory{ - StartTime: time.Now().Add(-30 * time.Hour), - EndTime: time.Now(), + StartTime: time.Now().Add(-30 * time.Hour).Unix(), + EndTime: time.Now().Unix(), }) assert.NoError(t, err) diff --git a/rest/request-public.go b/rest/request-public.go index 18ddaf0..455683b 100644 --- a/rest/request-public.go +++ b/rest/request-public.go @@ -1,8 +1,8 @@ package rest import ( - "github.com/go-numb/go-ftx/rest/public/futures" - "github.com/go-numb/go-ftx/rest/public/markets" + "github.com/boyi/go-ftx/rest/public/futures" + "github.com/boyi/go-ftx/rest/public/markets" ) func (p *Client) Markets(req *markets.RequestForMarkets) (*markets.ResponseForMarkets, error) { diff --git a/rest/request-public_test.go b/rest/request-public_test.go index 9c19192..90f13a6 100644 --- a/rest/request-public_test.go +++ b/rest/request-public_test.go @@ -8,9 +8,9 @@ import ( "time" "github.com/dustin/go-humanize" - "github.com/go-numb/go-ftx/rest" - "github.com/go-numb/go-ftx/rest/public/futures" - "github.com/go-numb/go-ftx/rest/public/markets" + "github.com/boyi/go-ftx/rest" + "github.com/boyi/go-ftx/rest/public/futures" + "github.com/boyi/go-ftx/rest/public/markets" "github.com/stretchr/testify/assert" ) diff --git a/rest/request.go b/rest/request.go index 5a818d5..9b2d59c 100644 --- a/rest/request.go +++ b/rest/request.go @@ -1,9 +1,6 @@ package rest import ( - "crypto/hmac" - "crypto/sha256" - "encoding/hex" "fmt" "net/url" "time" @@ -29,12 +26,6 @@ func (p *Client) request(req Requester, results interface{}) error { return nil } -func signature(secret, body string) string { - mac := hmac.New(sha256.New, []byte(secret)) - mac.Write([]byte(body)) - return hex.EncodeToString(mac.Sum(nil)) -} - func (p *Client) newRequest(r Requester) *fasthttp.Request { // avoid Pointer's butting u, _ := url.ParseRequestURI(ENDPOINT)