mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Binance: Update NewOrder API (#507)
Including new fields for request/response and allowing test orders. Signed-off-by: David Ackroyd <daveo.ackroyd@gmail.com>
This commit is contained in:
@@ -321,14 +321,35 @@ func (b *Binance) GetBestPrice(symbol string) (BestPrice, error) {
|
||||
// NewOrder sends a new order to Binance
|
||||
func (b *Binance) NewOrder(o *NewOrderRequest) (NewOrderResponse, error) {
|
||||
var resp NewOrderResponse
|
||||
if err := b.newOrder(newOrder, o, &resp); err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
path := b.API.Endpoints.URL + newOrder
|
||||
if resp.Code != 0 {
|
||||
return resp, errors.New(resp.Msg)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// NewOrderTest sends a new test order to Binance
|
||||
func (b *Binance) NewOrderTest(o *NewOrderRequest) error {
|
||||
var resp NewOrderResponse
|
||||
return b.newOrder(newOrderTest, o, &resp)
|
||||
}
|
||||
|
||||
func (b *Binance) newOrder(api string, o *NewOrderRequest, resp *NewOrderResponse) error {
|
||||
path := b.API.Endpoints.URL + api
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("symbol", o.Symbol)
|
||||
params.Set("side", o.Side)
|
||||
params.Set("type", string(o.TradeType))
|
||||
params.Set("quantity", strconv.FormatFloat(o.Quantity, 'f', -1, 64))
|
||||
if o.QuoteOrderQty > 0 {
|
||||
params.Set("quoteOrderQty", strconv.FormatFloat(o.QuoteOrderQty, 'f', -1, 64))
|
||||
} else {
|
||||
params.Set("quantity", strconv.FormatFloat(o.Quantity, 'f', -1, 64))
|
||||
}
|
||||
if o.TradeType == BinanceRequestParamsOrderLimit {
|
||||
params.Set("price", strconv.FormatFloat(o.Price, 'f', -1, 64))
|
||||
}
|
||||
@@ -352,14 +373,7 @@ func (b *Binance) NewOrder(o *NewOrderRequest) (NewOrderResponse, error) {
|
||||
params.Set("newOrderRespType", o.NewOrderRespType)
|
||||
}
|
||||
|
||||
if err := b.SendAuthHTTPRequest(http.MethodPost, path, params, limitOrder, &resp); err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Code != 0 {
|
||||
return resp, errors.New(resp.Msg)
|
||||
}
|
||||
return resp, nil
|
||||
return b.SendAuthHTTPRequest(http.MethodPost, path, params, limitOrder, resp)
|
||||
}
|
||||
|
||||
// CancelExistingOrder sends a cancel order to Binance
|
||||
|
||||
@@ -353,6 +353,47 @@ func TestGetOrderHistory(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOrderTest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
req := &NewOrderRequest{
|
||||
Symbol: "LTCBTC",
|
||||
Side: order.Buy.String(),
|
||||
TradeType: BinanceRequestParamsOrderLimit,
|
||||
Price: 0.0025,
|
||||
Quantity: 100000,
|
||||
TimeInForce: BinanceRequestParamsTimeGTC,
|
||||
}
|
||||
|
||||
err := b.NewOrderTest(req)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("NewOrderTest() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("NewOrderTest() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Mock NewOrderTest() error", err)
|
||||
}
|
||||
|
||||
req = &NewOrderRequest{
|
||||
Symbol: "LTCBTC",
|
||||
Side: order.Sell.String(),
|
||||
TradeType: BinanceRequestParamsOrderMarket,
|
||||
Price: 0.0045,
|
||||
QuoteOrderQty: 10,
|
||||
}
|
||||
|
||||
err = b.NewOrderTest(req)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("NewOrderTest() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("NewOrderTest() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Mock NewOrderTest() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -281,8 +281,10 @@ type NewOrderRequest struct {
|
||||
// TimeInForce specifies how long the order remains in effect.
|
||||
// Examples are (Good Till Cancel (GTC), Immediate or Cancel (IOC) and Fill Or Kill (FOK))
|
||||
TimeInForce RequestParamsTimeForceType
|
||||
// Quantity
|
||||
Quantity float64
|
||||
// Quantity is the total base qty spent or received in an order.
|
||||
Quantity float64
|
||||
// QuoteOrderQty is the total quote qty spent or received in a MARKET order.
|
||||
QuoteOrderQty float64
|
||||
Price float64
|
||||
NewClientOrderID string
|
||||
StopPrice float64 // Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.
|
||||
@@ -301,11 +303,13 @@ type NewOrderResponse struct {
|
||||
Price float64 `json:"price,string"`
|
||||
OrigQty float64 `json:"origQty,string"`
|
||||
ExecutedQty float64 `json:"executedQty,string"`
|
||||
Status string `json:"status"`
|
||||
TimeInForce string `json:"timeInForce"`
|
||||
Type string `json:"type"`
|
||||
Side string `json:"side"`
|
||||
Fills []struct {
|
||||
// The cumulative amount of the quote that has been spent (with a BUY order) or received (with a SELL order).
|
||||
CumulativeQuoteQty float64 `json:"cummulativeQuoteQty,string"`
|
||||
Status string `json:"status"`
|
||||
TimeInForce string `json:"timeInForce"`
|
||||
Type string `json:"type"`
|
||||
Side string `json:"side"`
|
||||
Fills []struct {
|
||||
Price float64 `json:"price,string"`
|
||||
Qty float64 `json:"qty,string"`
|
||||
Commission float64 `json:"commission,string"`
|
||||
|
||||
@@ -148,9 +148,6 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
|
||||
case http.MethodPost:
|
||||
for i := range mockResponses {
|
||||
cType, ok := mockResponses[i].Headers[contentType]
|
||||
if !ok {
|
||||
return errors.New("cannot find content type within mock responses")
|
||||
}
|
||||
|
||||
jCType := strings.Join(cType, "")
|
||||
var found bool
|
||||
@@ -190,7 +187,24 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
|
||||
mockResponses = append(mockResponses[:i], mockResponses[i+1:]...)
|
||||
found = true
|
||||
}
|
||||
case "":
|
||||
if !ok {
|
||||
// Assume query params are used
|
||||
mockQuery, urlErr := url.ParseQuery(mockResponses[i].QueryString)
|
||||
if urlErr != nil {
|
||||
return urlErr
|
||||
}
|
||||
|
||||
if MatchURLVals(mockQuery, res.Request.URL.Query()) {
|
||||
// if found will delete instance and overwrite with new data
|
||||
mockResponses = append(mockResponses[:i], mockResponses[i+1:]...)
|
||||
found = true
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
fallthrough
|
||||
default:
|
||||
return fmt.Errorf("unhandled content type %s", jCType)
|
||||
}
|
||||
|
||||
24
testdata/http_mock/binance/binance.json
vendored
24
testdata/http_mock/binance/binance.json
vendored
@@ -49951,6 +49951,30 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"/api/v3/order/test": {
|
||||
"POST": [
|
||||
{
|
||||
"data": null,
|
||||
"queryString": "price=0.0025\u0026quantity=100000\u0026recvWindow=5000\u0026side=BUY\u0026signature=1ddcd1b138325e4b72f045d56e719dc83963648001be999ca23ec88b94b1d900\u0026symbol=LTCBTC\u0026timeInForce=GTC\u0026timestamp=1589766515000\u0026type=LIMIT",
|
||||
"bodyParams": "",
|
||||
"headers": {
|
||||
"X-Mbx-Apikey": [
|
||||
""
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": null,
|
||||
"queryString": "quoteOrderQty=10\u0026recvWindow=5000\u0026side=SELL\u0026signature=f7d34dc6a9d6181adc3cd90f269a78d978610818b4d0b454ec95777194212aae\u0026symbol=LTCBTC\u0026timestamp=1589766516000\u0026type=MARKET",
|
||||
"bodyParams": "",
|
||||
"headers": {
|
||||
"X-Mbx-Apikey": [
|
||||
""
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"/api/v3/ticker/24hr": {
|
||||
"GET": [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user