mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
Fix Huobi's POST requests (#186)
* Fix Huobi's POST request content-type If we try to send a POST request to Huobi w/ a content-type of "application/x-www-form-urlencoded" we will receive an error: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported Their english documentation is incorrect, it does not specify this atm, translating their chinese documentation, it states: "Content-Type: application/json must be declared in the POST request header; Content-Type: application/x-www-form-urlencoded must be declared in the GET request header. (Chinese users recommend setting Accept-Language: zh-cn)" * Fix Huobi's place new order request (send as json) We should not send the order details through url parameters, this needs to be sent as a json payload via the request body. Documentation: https://github.com/huobiapi/API_Docs_en/wiki/REST_Reference#post-v1orderordersplace--make-an-order-in-huobipro * Fix Huobi's margin transfer/margin order/withdraw requests This requests data need to be sent as json, not as a query string. Docs: https://github.com/huobiapi/API_Docs_en/wiki/REST_Reference#post-v1dwtransfer-inmargin--transfer-asset-from-spot-account-to-margin-account https://github.com/huobiapi/API_Docs_en/wiki/REST_Reference#post-v1marginorders--margin-application https://github.com/huobiapi/API_Docs_en/wiki/REST_Reference#post-v1dwwithdrawapicreate---create-a-withdraw-application * Fix Huobi's margin repayment request This request data needs to be sent a json, not via the query string. Also note, that the "order-id" parameter is already sent through the url path, it does not need to be included in the request body.
This commit is contained in:
committed by
Adrian Gallagher
parent
7186ac2602
commit
604443fbbb
@@ -5,11 +5,13 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -338,7 +340,7 @@ func (h *HUOBI) GetAccounts() ([]Account, error) {
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiAccounts, url.Values{}, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiAccounts, url.Values{}, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -355,7 +357,7 @@ func (h *HUOBI) GetAccountBalance(accountID string) ([]AccountBalanceDetail, err
|
||||
|
||||
var result response
|
||||
endpoint := fmt.Sprintf(huobiAccountBalance, accountID)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", endpoint, url.Values{}, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", endpoint, url.Values{}, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -365,29 +367,36 @@ func (h *HUOBI) GetAccountBalance(accountID string) ([]AccountBalanceDetail, err
|
||||
|
||||
// SpotNewOrder submits an order to Huobi
|
||||
func (h *HUOBI) SpotNewOrder(arg SpotNewOrderRequestParams) (int64, error) {
|
||||
vals := url.Values{}
|
||||
vals.Set("account-id", fmt.Sprintf("%d", arg.AccountID))
|
||||
vals.Set("amount", strconv.FormatFloat(arg.Amount, 'f', -1, 64))
|
||||
data := struct {
|
||||
AccountID int `json:"account-id,string"`
|
||||
Amount string `json:"amount"`
|
||||
Price string `json:"price"`
|
||||
Source string `json:"source"`
|
||||
Symbol string `json:"symbol"`
|
||||
Type string `json:"type"`
|
||||
}{
|
||||
AccountID: arg.AccountID,
|
||||
Amount: strconv.FormatFloat(arg.Amount, 'f', -1, 64),
|
||||
Symbol: arg.Symbol,
|
||||
Type: string(arg.Type),
|
||||
}
|
||||
|
||||
// Only set price if order type is not equal to buy-market or sell-market
|
||||
if arg.Type != SpotNewOrderRequestTypeBuyMarket && arg.Type != SpotNewOrderRequestTypeSellMarket {
|
||||
vals.Set("price", strconv.FormatFloat(arg.Price, 'f', -1, 64))
|
||||
data.Price = strconv.FormatFloat(arg.Price, 'f', -1, 64)
|
||||
}
|
||||
|
||||
if arg.Source != "" {
|
||||
vals.Set("source", arg.Source)
|
||||
data.Source = arg.Source
|
||||
}
|
||||
|
||||
vals.Set("symbol", arg.Symbol)
|
||||
vals.Set("type", string(arg.Type))
|
||||
|
||||
type response struct {
|
||||
Response
|
||||
OrderID int64 `json:"data,string"`
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiOrderPlace, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiOrderPlace, nil, data, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return 0, errors.New(result.ErrorMessage)
|
||||
@@ -404,7 +413,7 @@ func (h *HUOBI) CancelOrder(orderID int64) (int64, error) {
|
||||
|
||||
var result response
|
||||
endpoint := fmt.Sprintf(huobiOrderCancel, strconv.FormatInt(orderID, 10))
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", endpoint, url.Values{}, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", endpoint, url.Values{}, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return 0, errors.New(result.ErrorMessage)
|
||||
@@ -420,7 +429,7 @@ func (h *HUOBI) CancelOrderBatch(orderIDs []int64) ([]CancelOrderBatch, error) {
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiOrderCancelBatch, url.Values{}, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiOrderCancelBatch, url.Values{}, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -437,7 +446,7 @@ func (h *HUOBI) GetOrder(orderID int64) (OrderInfo, error) {
|
||||
|
||||
var result response
|
||||
endpoint := fmt.Sprintf(huobiGetOrder, strconv.FormatInt(orderID, 10))
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", endpoint, url.Values{}, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", endpoint, url.Values{}, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return result.Order, errors.New(result.ErrorMessage)
|
||||
@@ -454,7 +463,7 @@ func (h *HUOBI) GetOrderMatchResults(orderID int64) ([]OrderMatchInfo, error) {
|
||||
|
||||
var result response
|
||||
endpoint := fmt.Sprintf(huobiGetOrderMatch, strconv.FormatInt(orderID, 10))
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", endpoint, url.Values{}, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", endpoint, url.Values{}, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -498,7 +507,7 @@ func (h *HUOBI) GetOrders(symbol, types, start, end, states, from, direct, size
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiGetOrders, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiGetOrders, vals, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -541,7 +550,7 @@ func (h *HUOBI) GetOrdersMatch(symbol, types, start, end, from, direct, size str
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiGetOrdersMatch, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiGetOrdersMatch, vals, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -551,10 +560,15 @@ func (h *HUOBI) GetOrdersMatch(symbol, types, start, end, from, direct, size str
|
||||
|
||||
// MarginTransfer transfers assets into or out of the margin account
|
||||
func (h *HUOBI) MarginTransfer(symbol, currency string, amount float64, in bool) (int64, error) {
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("currency", currency)
|
||||
vals.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
data := struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Currency string `json:"currency"`
|
||||
Amount string `json:"amount"`
|
||||
}{
|
||||
Symbol: symbol,
|
||||
Currency: currency,
|
||||
Amount: strconv.FormatFloat(amount, 'f', -1, 64),
|
||||
}
|
||||
|
||||
path := huobiMarginTransferIn
|
||||
if !in {
|
||||
@@ -567,7 +581,7 @@ func (h *HUOBI) MarginTransfer(symbol, currency string, amount float64, in bool)
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", path, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", path, nil, data, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return 0, errors.New(result.ErrorMessage)
|
||||
@@ -577,10 +591,15 @@ func (h *HUOBI) MarginTransfer(symbol, currency string, amount float64, in bool)
|
||||
|
||||
// MarginOrder submits a margin order application
|
||||
func (h *HUOBI) MarginOrder(symbol, currency string, amount float64) (int64, error) {
|
||||
vals := url.Values{}
|
||||
vals.Set("symbol", symbol)
|
||||
vals.Set("currency", currency)
|
||||
vals.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
data := struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Currency string `json:"currency"`
|
||||
Amount string `json:"amount"`
|
||||
}{
|
||||
Symbol: symbol,
|
||||
Currency: currency,
|
||||
Amount: strconv.FormatFloat(amount, 'f', -1, 64),
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Response
|
||||
@@ -588,7 +607,7 @@ func (h *HUOBI) MarginOrder(symbol, currency string, amount float64) (int64, err
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiMarginOrders, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiMarginOrders, nil, data, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return 0, errors.New(result.ErrorMessage)
|
||||
@@ -598,9 +617,11 @@ func (h *HUOBI) MarginOrder(symbol, currency string, amount float64) (int64, err
|
||||
|
||||
// MarginRepayment repays a margin amount for a margin ID
|
||||
func (h *HUOBI) MarginRepayment(orderID int64, amount float64) (int64, error) {
|
||||
vals := url.Values{}
|
||||
vals.Set("order-id", strconv.FormatInt(orderID, 10))
|
||||
vals.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
data := struct {
|
||||
Amount string `json:"amount"`
|
||||
}{
|
||||
Amount: strconv.FormatFloat(amount, 'f', -1, 64),
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Response
|
||||
@@ -609,7 +630,7 @@ func (h *HUOBI) MarginRepayment(orderID int64, amount float64) (int64, error) {
|
||||
|
||||
var result response
|
||||
endpoint := fmt.Sprintf(huobiMarginRepay, strconv.FormatInt(orderID, 10))
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", endpoint, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", endpoint, nil, data, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return 0, errors.New(result.ErrorMessage)
|
||||
@@ -653,7 +674,7 @@ func (h *HUOBI) GetMarginLoanOrders(symbol, currency, start, end, states, from,
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiMarginLoanOrders, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiMarginLoanOrders, vals, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -674,7 +695,7 @@ func (h *HUOBI) GetMarginAccountBalance(symbol string) ([]MarginAccountBalance,
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiMarginAccountBalance, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("GET", huobiMarginAccountBalance, vals, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return nil, errors.New(result.ErrorMessage)
|
||||
@@ -689,21 +710,28 @@ func (h *HUOBI) Withdraw(address, currency, addrTag string, amount, fee float64)
|
||||
WithdrawID int64 `json:"data"`
|
||||
}
|
||||
|
||||
vals := url.Values{}
|
||||
vals.Set("address", address)
|
||||
vals.Set("currency", currency)
|
||||
vals.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
data := struct {
|
||||
Address string `json:"address"`
|
||||
Amount string `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
Fee string `json:"fee"`
|
||||
AddrTag string `json:"addr-tag"`
|
||||
}{
|
||||
Address: address,
|
||||
Currency: currency,
|
||||
Amount: strconv.FormatFloat(amount, 'f', -1, 64),
|
||||
}
|
||||
|
||||
if fee != 0 {
|
||||
vals.Set("fee", strconv.FormatFloat(fee, 'f', -1, 64))
|
||||
data.Fee = strconv.FormatFloat(fee, 'f', -1, 64)
|
||||
}
|
||||
|
||||
if currency == "XRP" {
|
||||
vals.Set("addr-tag", addrTag)
|
||||
data.AddrTag = addrTag
|
||||
}
|
||||
|
||||
var result response
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiWithdrawCreate, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", huobiWithdrawCreate, nil, data, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return 0, errors.New(result.ErrorMessage)
|
||||
@@ -723,7 +751,7 @@ func (h *HUOBI) CancelWithdraw(withdrawID int64) (int64, error) {
|
||||
|
||||
var result response
|
||||
endpoint := fmt.Sprintf(huobiWithdrawCancel, strconv.FormatInt(withdrawID, 10))
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", endpoint, vals, &result)
|
||||
err := h.SendAuthenticatedHTTPRequest("POST", endpoint, vals, nil, &result)
|
||||
|
||||
if result.ErrorMessage != "" {
|
||||
return 0, errors.New(result.ErrorMessage)
|
||||
@@ -737,11 +765,15 @@ func (h *HUOBI) SendHTTPRequest(path string, result interface{}) error {
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API
|
||||
func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Values, result interface{}) error {
|
||||
func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Values, data interface{}, result interface{}) error {
|
||||
if !h.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, h.Name)
|
||||
}
|
||||
|
||||
if values == nil {
|
||||
values = url.Values{}
|
||||
}
|
||||
|
||||
values.Set("AccessKeyId", h.APIKey)
|
||||
values.Set("SignatureMethod", "HmacSHA256")
|
||||
values.Set("SignatureVersion", "2")
|
||||
@@ -752,7 +784,12 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url
|
||||
method, endpoint, values.Encode())
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
if method == http.MethodGet {
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
} else {
|
||||
headers["Content-Type"] = "application/json"
|
||||
}
|
||||
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(payload), []byte(h.APISecret))
|
||||
signature := common.Base64Encode(hmac)
|
||||
@@ -789,5 +826,16 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url
|
||||
url := fmt.Sprintf("%s%s", h.APIUrl, endpoint)
|
||||
url = common.EncodeURLValues(url, values)
|
||||
|
||||
return h.SendPayload(method, url, headers, bytes.NewBufferString(""), result, true, h.Verbose)
|
||||
var body []byte
|
||||
|
||||
if data != nil {
|
||||
encoded, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Huobi unable to marshal data: %s", err)
|
||||
}
|
||||
|
||||
body = encoded
|
||||
}
|
||||
|
||||
return h.SendPayload(method, url, headers, bytes.NewReader(body), result, true, h.Verbose)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user